package com.rt.schedulenew.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.rt.schedulebase.dto.*;
import com.rt.schedulebase.entity.*;
import com.rt.schedulebase.mapper.*;
import com.rt.schedulenew.api.*;
import com.rt.schedulenew.dto.DictScheduleApmDutyDto;
import com.rt.schedulenew.dto.SignScheduleDto;
import com.rt.schedulenew.dto.WaitingDto;
import com.rt.schedulenew.utils.base.BigDecimalUtil;
import com.rt.schedulenew.utils.base.CommonUtil;
import com.rt.schedulenew.utils.base.ConstantsUtil;
import com.rt.schedulenew.utils.global.BusinessException;
import com.rt.schedulenew.utils.global.JsonResult;
import com.rt.schedulenew.utils.global.JsonResultUtil;
import com.rt.schedulenew.utils.pkgenerator.PKGeneratorSingle;
import com.rt.schedulenew.utils.util.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.client.ResourceAccessException;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CommonServiceImpl implements ICommonService {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DictHospitalMapper dictHospitalMapper;
    @Autowired
    private IDictHospitalService dictHospitalService;
    @Autowired
    private DictItemGroupMapper dictItemGroupMapper;
    @Autowired
    private DictScheduleApmMapper dictScheduleApmMapper;
    @Autowired
    private ExamPatientMapper examPatientMapper;
    @Autowired
    private ExamApplyMapper examApplyMapper;
    @Autowired
    private ExamReferMapper examReferMapper;
    @Autowired
    private ExamScheduleMapper examScheduleMapper;
    @Autowired
    private ExamScheduleItemMapper examScheduleItemMapper;
    @Autowired
    private ExamScheduleActMapper examScheduleActMapper;
    @Autowired
    private ExamScheduleApmMapper examScheduleApmMapper;
    @Autowired
    private ExamScheduleApmRegularMapper examScheduleApmRegularMapper;
    @Autowired
    private ExamApplyItemMapper examApplyItemMapper;
    @Autowired
    private DictExamQueueMapper dictExamQueueMapper;
    @Autowired
    private DictScheduleApmRegularMapper dictScheduleApmRegularMapper;
    @Autowired
    private IDictRoleFunctionService dictRoleFunctionService;
    @Autowired
    private CacheServiceImpl cacheServiceImpl;
    @Autowired
    private ConfigServiceImpl configServiceImpl;
    @Autowired
    private DictScheduleApmRegularServiceImpl dictScheduleApmRegularServiceImpl;
    @Autowired
    private ExamApplyPatientMapper examApplyPatientMapper;
    @Autowired
    private IExamSmsNoticeService examSmsNoticeService;
    @Autowired
    private IDictSmsContentService dictSmsContentService;
    @Autowired
    private IDictCommonUseService dictCommonUseService;
    @Autowired
    private DictScheduleApmServiceImpl dictScheduleApmService;
    @Autowired
    private IExamsService examsService;
    @Autowired
    private DictExamItemMapper dictExamItemMapper;
    @Autowired
    private IExamReferService examReferService;
    @Autowired
    private IExamReferItemService examReferItemService;
    @Autowired
    private IExamScheduleService examScheduleService;
    @Autowired
    private ExamScheduleItemServiceImpl examScheduleItemServiceImpl;
    @Autowired
    private DictScheduleApmDutyServiceImpl dictScheduleApmDutyServiceImpl;
    @Autowired
    private RuleEngineServiceImpl ruleEngineServiceImpl;
    @Autowired
    private IExamApplyOrganService examApplyOrganService;
    @Autowired
    private IExamApplyPatientIdService examApplyPatientIdService;
    @Autowired
    private ExamQueueMapper examQueueMapper;
    @Autowired
    private ExamItemMapper examItemMapper;
    @Autowired
    private IDictDeptService dictDeptService;
    @Autowired
    private IDictExamQueueService dictExamQueueService;
    @Autowired
    private IExamScheduleApmService examScheduleApmService;
    @Autowired
    private IDictExamClassService dictExamClassService;
    @Autowired
    private ConfigServiceImpl configService;
    @Autowired
    private IExamScheduleActService actService;
    @Autowired
    private IDictSerialService dictSerialService;
    @Autowired
    private IScheduleSignService scheduleSignService;
    @Autowired
    DataSourceTransactionManager transactionManager;

    @Autowired
    DictExamScheduleNoMapper dictExamScheduleNoMapper;

    @Override
    public List<String> getSickIds(ExamApplyDto dto) {
        String commonCard = configServiceImpl.getIcCardPre(dto.getCommonCard());
        Map<String, String> map = new HashMap<String, String>();
        map.put("commonCard", commonCard);
        String inputSupport = configServiceImpl.getIcCardInputSupport();
        if (inputSupport.contains("ic_card")) {
            map.put("supportByIcCard", "1");
        }
        if (inputSupport.contains("inpatient_no")) {
            map.put("supportByInpatientNo", "1");
        }
        if (inputSupport.contains("outpatient_no")) {
            map.put("supportByOutpatientNo", "1");
        }
        if (inputSupport.contains("identity_card")) {
            map.put("supportByIdentityCard", "1");
        }
        if (inputSupport.contains("mi_card")) {
            map.put("supportByMiCard", "1");
        }
        if (inputSupport.contains("sick_id")) {
            map.put("supportBySickId", "1");
        }
        if (inputSupport.contains("apply_no")) {
            map.put("supportByApplyNo", "1");
        }
        if (inputSupport.contains("health_card")) {
            map.put("supportByHealthCard", "1");
        }
        if (inputSupport.contains("out_reg_no")) {
            map.put("supportByOutRegNo", "1");
        }
        if (inputSupport.contains("case_no")) {
            map.put("supportByOutCaseNo", "1");
        }
        map.put("icCard", dto.getIcCard());
        map.put("sickId", dto.getSickId());
        map.put("identityCard", dto.getIdentityCard());
        map.put("inpatientNo", dto.getInpatientNo());
        map.put("outpatientNo", dto.getOutpatientNo());
        map.put("applyNo", dto.getApplyNo());
        map.put("miCard", dto.getMiCard());
        map.put("healthCard", dto.getHealthCard());
        map.put("outRegNo", dto.getOutRegNo());
        map.put("caseNo", dto.getCaseNo());
        List<String> sickIds;
        if ("1".equals(dto.getIsRefer())) {
            sickIds = examReferMapper.getSickIds(map);
        } else {
            sickIds = examApplyMapper.getSickIds(map);
            if (sickIds.size() == 0) {
                sickIds = examApplyPatientMapper.getSickIds(map);
            }
        }
        if (StringUtils.isNotBlank(commonCard)) {
            List<String> sickIds4DomainId = getSickIds4DomainId(commonCard);
            if (sickIds4DomainId != null && !sickIds4DomainId.isEmpty()) {
                sickIds.addAll(sickIds4DomainId);
            }
        }
        return sickIds;
    }

    public List<String> getSickIds4DomainId(String commonCard) {
        List<String> sickIds4DomainId = new ArrayList<String>();
        List<String> domainIdList = configServiceImpl.getIcCardInputNewSupport();
        if (!domainIdList.isEmpty()) {
            ExamApplyPatientIdDto examApplyPatientIdDto = new ExamApplyPatientIdDto();
            examApplyPatientIdDto.setPatientId(commonCard);
            examApplyPatientIdDto.setDomainIdList(domainIdList);
            List<ExamApplyPatientId> examApplyPatientIdList = (List<ExamApplyPatientId>) examApplyPatientIdService.selectList(examApplyPatientIdDto);
            if (examApplyPatientIdList != null && !examApplyPatientIdList.isEmpty()) {
                for (ExamApplyPatientId examApplyPatientId : examApplyPatientIdList) {
                    sickIds4DomainId.add(examApplyPatientId.getSickId());
                }
            }
        }
        return sickIds4DomainId;
    }

    /***
     * 获取检查项目冲突排序优先级
     * @param mergeMap
     * @param itemCodes_i
     * @param itemCodes_j
     * @param itemGroupMap
     * @return
     */
    public int existsGroup(Map<String, Object> mergeMap, List<String> itemCodes_i, List<String> itemCodes_j, Map<String, List<Map<String, Object>>> itemGroupMap) {
        int groupPriority = 0;
        List<String> itemCodesAll = new ArrayList<>();
        itemCodesAll.addAll(itemCodes_i);
        itemCodesAll.addAll(itemCodes_j);

        String examClass = mergeMap.get("examClass") + "";
        String patientSource = (mergeMap.get("patientSource") == null) ? "" : (mergeMap.get("patientSource") + "");
        String deptCode = (mergeMap.get("deptCode") == null) ? "" : (mergeMap.get("deptCode") + "");
        String iReqDept = (mergeMap.get("reqDept_i") == null) ? "" : (mergeMap.get("reqDept_i") + "");
        String jReqDept = (mergeMap.get("reqDept_j") == null) ? "" : (mergeMap.get("reqDept_j") + "");

        String itemBeforeConfigStr = configService.getConfigByName(ConstantsUtil.ConfigName.ITEM_BEFORE.getKey());
        List<ConfigDto.ItemBefore> list = JsonUtil.toList(itemBeforeConfigStr, ConfigDto.ItemBefore.class);
        if (!CollectionUtils.isEmpty(list)) {
            for (ConfigDto.ItemBefore itemBefore : list) {
                List<DictExamItem> dictExamItemA = itemBefore.getExamItemA();
                List<DictExamItem> dictExamItemB = itemBefore.getExamItemB();
                List<String> itemCode_A = new ArrayList<>();

                if (dictExamItemA != null) {
                    for (DictExamItem dei : dictExamItemA) {
                        if (!examClass.equals(dei.getExamClass())) {
                            continue;
                        }
                        if (!itemCodesAll.contains(dei.getItemCode())) {
                            continue;
                        }
                        itemCode_A.add(dei.getItemCode());
                    }
                    if (itemCode_A.size() == 0) {
                        continue;
                    }
                }
                if (dictExamItemB != null) {
                    for (DictExamItem dei : dictExamItemB) {
                        if (!examClass.equals(dei.getExamClass())) {
                            continue;
                        }
                        if (itemCode_A.size() != itemCodesAll.size() && itemCode_A.contains(dei.getItemCode())) {
                            continue;
                        }
                        if (itemCodesAll.contains(dei.getItemCode())) {
                            return groupPriority;
                        }
                    }
                }
            }
        }
        for (Map.Entry<String, List<Map<String, Object>>> entry : itemGroupMap.entrySet()) {
            if (!examClass.equals(entry.getKey())) {
                continue;
            }
            int sortNoMax = 0;
            int otherSortNoMax = 0;
            for (Map<String, Object> map : entry.getValue()) {
                String priorityOrderGroup = map.get("priorityOrder") + "";
                String itemCodeGroup = map.get("itemCode") + "";
                String patientSourceGroup = (map.get("patientSource") == null) ? patientSource : (map.get("patientSource") + "");
                String deptCodeGroup = (map.get("deptCode") == null) ? deptCode : (map.get("deptCode") + "");
                List<String> itemCodeGroupList = CommonUtil.split2List(itemCodeGroup);
                if (itemCodeGroupList.size() <= 1) {
                    continue;
                }
                if (!patientSourceGroup.equals(patientSource)) {
                    continue;
                }
                if (!deptCodeGroup.equals(deptCode)) {
                    continue;
                }
                String reqDeptGroup = (map.get("reqDept") == null) ? "" : (map.get("reqDept") + "");
                List<String> reqDeptGroupList = CommonUtil.split2List(reqDeptGroup);
                if (StringUtils.isNotBlank(reqDeptGroup)) {
                    if (!reqDeptGroupList.contains(iReqDept)) {
                        continue;
                    }
                    if (!reqDeptGroupList.contains(jReqDept)) {
                        continue;
                    }
                }
                if (itemCodeGroupList.containsAll(itemCodesAll) && Integer.parseInt(priorityOrderGroup) > sortNoMax) {
                    sortNoMax = Integer.parseInt(priorityOrderGroup);
                }
                if (itemCodes_j == null || itemCodes_j.size() <= 0) {
                    continue;
                }
                boolean isOther = true;
                for (String itemCode_i : itemCodes_i) {
                    if (itemCodeGroupList.contains(itemCode_i)) {
                        isOther = false;
                    }
                }
                if (!isOther || !itemCodeGroupList.containsAll(itemCodes_j) || Integer.parseInt(priorityOrderGroup) <= otherSortNoMax) {
                    continue;
                }
                otherSortNoMax = Integer.parseInt(priorityOrderGroup);
            }
            if (sortNoMax > 0) {
                groupPriority = sortNoMax;
            }
            if (sortNoMax >= otherSortNoMax) {
                continue;
            }
            groupPriority = 0;
        }
        return groupPriority;
    }

    /**
     * 合并和查询申请单状态
     *
     * @param examApplyDto
     * @param historyFlag
     * @param terminalType
     * @param isMergeChannel
     * @return
     */
    @Override
    public List<ExamApplyDto> mergeApply(List<ExamApplyDto> examApplyDto, String historyFlag, String terminalType, String isMergeChannel) {
        List<ExamApplyDto> lsExamApplyDto = new ArrayList<>();
        // 检查编码列表
        List<String> itemCodeList = new ArrayList<>();
        for (ExamApplyDto applyDto : examApplyDto) {
            ExamApplyItemDto examApplyItemDto = new ExamApplyItemDto();
            examApplyItemDto.setApplyNo(applyDto.getApplyNo());
            List<ExamApplyItemDto> items;
            // 判断是否虚单预约
            if (applyDto.getApplyNo().contains("RE")) {
                // 获取虚单预约申请项目列表
                items = examApplyItemMapper.getReItemList(examApplyItemDto);
            } else {
                // 获取申请单号的检查项目列表
                items = examApplyItemMapper.getList(examApplyItemDto);
            }
            // 绑定检查项目的 编码和子项信息 去掉检查子项为空的项目
            handItemCode(items, applyDto.getExamSubClass());
            // 非历史记录-才校验
            if (StringUtils.isBlank(historyFlag) || "1".equals(historyFlag)) {
                // 去掉已预约 超时且没有报道的数据
                applyDto = configServiceImpl.noShowScheduleItem(applyDto, items, terminalType);
                if (applyDto == null) {
                    continue;
                }
            }
            // 非历史记录
            if (StringUtils.isNotBlank(historyFlag)) {
                Iterator<ExamApplyItemDto> it = items.iterator();
                while (it.hasNext()) {
                    ExamApplyItemDto eai = it.next();
                    // 检查状态
                    int itemStatus = Integer.parseInt(StringUtils.isBlank(eai.getExamStatus()) ? "0" : eai.getExamStatus());
                    if (itemStatus == 0) {
                        // 预约检查状态
                        itemStatus = Integer.parseInt(StringUtils.isBlank(eai.getScheduleStatus()) ? "0" : eai.getScheduleStatus());
                    }
                    if ("1".equals(historyFlag)) {
                        if (itemStatus >= 40 || itemStatus == 4) {
                            it.remove();
                        } else {
                            if (itemStatus >= 10) {
                                continue;
                            }
                            int amount = (eai.getAmount() != null) ? eai.getAmount() : 1;
                            int regAmount = (eai.getRegAmount() != null) ? eai.getRegAmount() : 0;
                            if (regAmount < amount) {
                                continue;
                            }
                            // 已报到的申请项目-直接去掉不展示
                            it.remove();
                        }
                    } else {
                        if (itemStatus >= 40) {
                            continue;
                        }
                        it.remove();
                    }
                }
            }

            // 检查项目为空
            if (CollectionUtils.isEmpty(items)) {
                continue;
            }
            // 合单预约 合并到一起
            Map<String, List<ExamApplyItemDto>> map = new HashMap<>();
            for (ExamApplyItemDto itemDto : items) {
                itemDto.setReqDate(applyDto.getReqDate());
                itemDto.setReqTime(applyDto.getReqTime());
                itemDto.setReqDept(applyDto.getReqDept());
                itemDto.setReqDeptName(applyDto.getReqDeptName());
                itemDto.setReqPhysician(applyDto.getReqPhysician());
                itemDto.setSickId(applyDto.getSickId());
                itemDto.setClinSymp(applyDto.getClinSymp());
                itemDto.setClinDiag(applyDto.getClinDiag());
                // 须知注意事项
                itemDto.setReqNotice(applyDto.getNotice());
                // 是否缴费
                itemDto.setChargeFlag(StringUtils.isBlank(applyDto.getChargeFlag()) ? "0" : applyDto.getChargeFlag());
                // 来源
                itemDto.setPatientSource(StringUtils.isBlank(applyDto.getPatientSource()) ? "" : applyDto.getPatientSource());
                itemDto.setPrintCnt(applyDto.getPrintCnt() != null ? applyDto.getPrintCnt() : "0");
                List<ExamApplyItemDto> itemDtos = new ArrayList<>();
                itemDtos.add(itemDto);

                // 判断检查项目是否可以正常操作
                String msg = isScheduleByFlags(itemDtos, terminalType, applyDto.getChargeType());
                if (StringUtils.isNotBlank(msg)) {
                    itemDto.setUnclickable("1");
                } else {
                    itemDto.setUnclickable("0");
                }
                itemCodeList.add(itemDto.getItemCode());
                List<ExamApplyItemDto> newitem = new ArrayList<>();
                String queueNo = StringUtils.isBlank(itemDto.getQueueNo()) ? "" : itemDto.getQueueNo();
                // 预约id
                String id = StringUtils.isBlank(itemDto.getScheduledId()) ? "" : itemDto.getScheduledId();
                // 预约id + 排队队列
                String scheduleId = id + queueNo;
                if (map.containsKey(scheduleId)) {
                    newitem.add(itemDto);
                    for (String key : map.keySet()) {
                        if (!key.equals(scheduleId)) {
                            continue;
                        }
                        List<ExamApplyItemDto> value = map.get(key);
                        newitem.addAll(value);
                    }
                    map.put(scheduleId, newitem);
                } else {
                    newitem.add(itemDto);
                    map.put(scheduleId, newitem);
                }
            }
            for (Map.Entry<String, List<ExamApplyItemDto>> vo : map.entrySet()) {
                ExamApplyDto newEa = new ExamApplyDto();
                BeanUtils.copyProperties(applyDto, newEa);
                newEa.setItems(vo.getValue());
                List<ExamApplyDto> list = new ArrayList<>();
                list.add(newEa);
                lsExamApplyDto.addAll(list);
            }
        }
        // 检查分组
        DictItemGroupDto itemGroup = new DictItemGroupDto();
        itemGroup.setItemCodeList(itemCodeList);
        itemGroup.setGroupType("0");
        List<DictItemGroupDto> examItemGroupList = dictItemGroupMapper.getGroupList(itemGroup);

        Map<String, List<Map<String, Object>>> itemGroupMap = new HashMap<>();
        if (examItemGroupList != null && examItemGroupList.size() > 0) {
            // 分组检查项目
            Map<String, List<String>> groupMap = new HashMap<>();
            Map<String, Map<String, Object>> groupCodeMap = new HashMap<>();
            for (DictItemGroupDto groupList : examItemGroupList) {
                String groupKey = groupList.getExamClass() + "=" + groupList.getGroupCode();
                if (groupMap.containsKey(groupKey)) {
                    List<String> itemCodes = groupMap.get(groupKey);
                    itemCodes.add(groupList.getItemCode());
                } else {
                    List<String> itemCodes = new ArrayList<>();
                    itemCodes.add(groupList.getItemCode());
                    groupMap.put(groupKey, itemCodes);

                    // 分组优先级
                    int priorityOrder = (groupList.getPriorityOrder() == null) ? 1 : groupList.getPriorityOrder();
                    // 分组特性
                    Map<String, Object> gropAttr = new HashMap<>();
                    gropAttr.put("priorityOrder", priorityOrder);
                    // 分组来源
                    gropAttr.put("patientSource", groupList.getPatientSource());
                    gropAttr.put("deptCode", groupList.getDeptCode());
                    gropAttr.put("reqDept", groupList.getReqDept());
                    groupCodeMap.put(groupList.getGroupCode(), gropAttr);
                }
            }

            for (Map.Entry<String, List<String>> group : groupMap.entrySet()) {
                String[] groupKey = group.getKey().split("=");

                List<String> itemCodes = group.getValue();
                String examClass = groupKey[0];
                String groupCode = groupKey[1];
                Map<String, Object> maps = groupCodeMap.get(groupCode);
                maps.put("itemCode", StringUtils.join(itemCodes, ","));
                // 检查类别
                List<Map<String, Object>> examClassItemCodes = new ArrayList<>();
                if (itemGroupMap.containsKey(examClass)) {
                    examClassItemCodes = itemGroupMap.get(examClass);
                }
                examClassItemCodes.add(maps);
                itemGroupMap.put(examClass, examClassItemCodes);
            }
        }

        // 合单检查
        int size = lsExamApplyDto.size();
        for (int i = 0; i < size; ++i) {
            ExamApplyDto ea_i = lsExamApplyDto.get(i);
            if (!StringUtils.isNotBlank(ea_i.getMergeFlag()) || !StringUtils.isBlank(ea_i.getGroupFlag())) {
                int mergeDateLimit = -1;
                // 获取设置的可以合并的项目
                String mergeItem = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.MERGE_ITEM.getKey());
                List<ConfigDto.MergeItem> mergeItemList;
                if (StringUtils.isNotBlank(mergeItem)) {
                    mergeItemList = JsonUtil.toList(mergeItem, ConfigDto.MergeItem.class);
                    if (mergeItemList != null && mergeItemList.size() > 0) {
                        for (ConfigDto.MergeItem item : mergeItemList) {
                            List<String> examClassList = item.getExamClass();
                            if (examClassList.contains(ea_i.getExamClass())) {
                                mergeDateLimit = Integer.parseInt(item.getMergeDateTime());
                            }
                        }
                    }
                }
                ea_i.setMergeDateLimit(mergeDateLimit);

                List<String> itemCodes_i = ea_i.getItems().stream().map(x -> x.getItemCode()).collect(Collectors.toList());

                boolean isMerge = false;
                String scheduleId2 = "";
                if (StringUtils.isNotBlank(ea_i.getItems().get(0).getScheduledId())) {
                    String queueNo2 = StringUtils.isBlank(ea_i.getItems().get(0).getQueueNo()) ? "" : ea_i.getItems().get(0).getQueueNo();
                    String id2 = StringUtils.isBlank(ea_i.getItems().get(0).getScheduledId()) ? "" : ea_i.getItems().get(0).getScheduledId();
                    scheduleId2 = id2 + queueNo2;
                    isMerge = true;
                }
                if (StringUtils.isNotBlank(isMergeChannel)) {
                    isMerge = true;
                }
                Map<String, Object> mergeMap = new HashMap<>();
                mergeMap.put("examClass", ea_i.getExamClass());
                mergeMap.put("patientSource", ea_i.getPatientSource());
                mergeMap.put("deptCode", ea_i.getPerformDept());
                mergeMap.put("reqDept_i", ea_i.getReqDept());
                mergeMap.put("reqDept_j", ea_i.getReqDept());
                if (!isMerge) {
                    int groupPriority = existsGroup(mergeMap, itemCodes_i, new ArrayList<String>(), itemGroupMap);
                    if (groupPriority > 0) {
                        isMerge = true;
                    }
                }
                if (isMerge) {
                    int maxGroup = 0;
                    Map<String, Object> groupMap2 = new HashMap<String, Object>();
                    for (int j = i + 1; j < size; ++j) {
                        ExamApplyDto ea_j = lsExamApplyDto.get(j);
                        if (!StringUtils.isNotBlank(ea_j.getMergeFlag()) || !StringUtils.isBlank(ea_j.getGroupFlag())) {
                            String no = StringUtils.isBlank(ea_j.getItems().get(0).getQueueNo()) ? "" : ea_j.getItems().get(0).getQueueNo();
                            String schId = StringUtils.isBlank(ea_j.getItems().get(0).getScheduledId()) ? "" : ea_j.getItems().get(0).getScheduledId();
                            String schIdJ = schId + no;
                            if (scheduleId2.equals(schIdJ)) {
                                List<String> itemCodes_j = new ArrayList<String>();
                                boolean isMerge_j = false;
                                if (StringUtils.isNotBlank(ea_j.getItems().get(0).getScheduledId()) && ea_i.getItems().get(0).getScheduledId().equals(ea_j.getItems().get(0).getScheduledId())) {
                                    isMerge_j = true;
                                }
                                if (!isMerge_j) {
                                    boolean isChannel = StringUtils.isNotBlank(isMergeChannel);
                                    String isCompliance = mergeRule(itemCodes_i, itemCodes_j, ea_i, ea_j, isChannel);
                                    if (StringUtils.isNotBlank(isCompliance)) {
                                        continue;
                                    }
                                }
                                if (StringUtils.isNotBlank(isMergeChannel)) {
                                    isMerge_j = true;
                                }
                                if (isMerge_j) {
                                    List<ExamApplyItemDto> lsItem = ea_i.getItems();
                                    lsItem.addAll(ea_j.getItems());
                                    ea_i.setMergeFlag("1");
                                    ea_j.setMergeFlag("0");
                                }
                                mergeMap.put("reqDept_j", ea_j.getReqDept());
                                if (!isMerge_j) {
                                    int groupPriority2 = existsGroup(mergeMap, itemCodes_i, itemCodes_j, itemGroupMap);
                                    if (groupPriority2 > 0 && groupPriority2 > maxGroup) {
                                        String groupMapKey = ea_j.getApplyNo() + ea_j.getItems().get(0).getItemNo();
                                        maxGroup = groupPriority2;
                                        groupMap2 = new HashMap<String, Object>();
                                        groupMap2.put(groupMapKey, groupPriority2);
                                    }
                                }
                            }
                        }
                    }
                    for (int j = i + 1; j < size; ++j) {
                        ExamApplyDto ea_j = lsExamApplyDto.get(j);
                        if (!StringUtils.isNotBlank(ea_j.getMergeFlag())) {
                            String groupMapKey2 = ea_j.getApplyNo() + ea_j.getItems().get(0).getItemNo();
                            if (groupMap2.containsKey(groupMapKey2)) {
                                List<ExamApplyItemDto> lsItem_j = ea_j.getItems();
                                lsItem_j.addAll(ea_i.getItems());
                                ea_i.setMergeFlag("0");
                                ea_j.setMergeFlag("1");
                                ea_j.setGroupFlag("1");
                            }
                        }
                    }
                }
            }
        }

        Iterator<ExamApplyDto> it2 = lsExamApplyDto.iterator();
        while (it2.hasNext()) {
            ExamApplyDto apply = it2.next();
            //StringBuffer sf = new StringBuffer();
            if ("0".equals(apply.getMergeFlag())) {
                it2.remove();
            } else {
                collectionSort(apply.getItems(), true);
                boolean isSet = true;
                StringBuffer bf = new StringBuffer();
                String unclickable = "";
                for (ExamApplyItemDto applyItem : apply.getItems()) {
                    unclickable += applyItem.getUnclickable();
                    // 获取检查状态，先取检查状态，再取预约状态
                    String scheduleStatus = StringUtils.isNotBlank(applyItem.getExamStatus()) ? applyItem.getExamStatus() : applyItem.getScheduleStatus();
                    applyItem.setScheduleStatus(CommonUtil.turnScheduleStatus(scheduleStatus));
                    // 【“已取消”预约状态】(1：关闭   0：启用)，注：对“未预约”申请单细分为“已取消”，且该预约状态的申请单不推荐预约时间
                    String cancelFlag = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_CANCEL_FLAG.getKey());
                    if ("0".equals(cancelFlag) && StringUtils.isBlank(scheduleStatus) && applyItem.getScheCancel() != null) {
                        applyItem.setIsCancel("1");
                        apply.setIsCancel("1");
                    }
                    // 预约时段信息
                    applyItem.setScheduleApm(StringUtils.isNotBlank(apply.getExamApm()) ? apply.getExamApm() : applyItem.getScheduleApm());
                    if (StringUtils.isNotBlank(applyItem.getScheduleHospital())) {
                        DictHospital h = dictHospitalService.getHospital(applyItem.getScheduleHospital());
                        if (h != null) {
                            String hospitalName = h.getHospitalAlias();
                            if (StringUtils.isBlank(hospitalName)) {
                                hospitalName = h.getHospitalName();
                            }
                            applyItem.setScheduleHospitalName(hospitalName);
                            applyItem.setScheduleHospitalCode(h.getHospitalCode());
                        }
                    }
                    String mergeNo = applyItem.getApplyNo() + "-" + applyItem.getItemNo();
                    applyItem.setMergeNo(mergeNo);
                    bf.append("," + mergeNo);
                    if (isSet && apply.getApplyNo().equals(applyItem.getApplyNo())) {
                        isSet = false;
                        String queueName = StringUtils.isBlank(applyItem.getQueueAlias()) ? applyItem.getQueueName() : applyItem.getQueueAlias();
                        apply.setScheduleDate(applyItem.getScheduleDate());
                        apply.setScheduleStatus(applyItem.getScheduleStatus());
                        apply.setScheduleApm(applyItem.getScheduleApm());
                        apply.setScheduledTime(applyItem.getScheduledTime());
                        apply.setScheduleOrgans(applyItem.getScheduleOrgans());
                        apply.setNextApmRatio(applyItem.getNextApmRatio());
                        apply.setScheduledId(applyItem.getScheduledId());
                        apply.setChargeFlag(applyItem.getChargeFlag());
                        apply.setQueueName(applyItem.getQueueName());
                        apply.setQueueAlias(queueName);
                        apply.setQueueNo(applyItem.getQueueNo());
                        apply.setScheduleHospitalName(applyItem.getScheduleHospitalName());
                        apply.setScheduleHospitalCode(applyItem.getScheduleHospitalCode());
                        apply.setTimeSignin(applyItem.getTimeSignin());
                        apply.setMemo(applyItem.getMemo());
                        apply.setRegularIdList(Arrays.asList(applyItem.getRegularId()));
                        apply.setPatLocalId(applyItem.getPatLocalId());
                        apply.setOrderNo(applyItem.getOrderNo());
                        apply.setApmCode(applyItem.getApmCode());
                        if ("2".equals(historyFlag)) {
                            apply.setCheckTime(getExamActForActDate(apply.getApplyNo()));
                        }
                    }
                    if (StringUtils.isNotBlank(applyItem.getScheduledId())) {
                        continue;
                    }
                }
                apply.setUnclickable(unclickable.contains("0") ? "0" : "1");
                apply.setMergeNo(bf.substring(1));
                boolean isExamClass4Organ = configServiceImpl.getOrganExamClassList().contains(apply.getExamClass());
                double reqCount = 1.0;
                if (isExamClass4Organ) {
                    reqCount = getReqOrganByItems(apply.getItems());
                }
                apply.setReqRatio(String.valueOf(reqCount));
            }
        }

        for (ExamApplyDto applyDto : lsExamApplyDto) {
            StringBuffer itemNames = new StringBuffer();
            StringBuffer itemCodes3 = new StringBuffer();
            StringBuffer itemFlags = new StringBuffer();
            StringBuffer examSubClass = new StringBuffer();
            StringBuffer organNames = new StringBuffer();
            List<String> examRequires = new ArrayList<>();
            List<String> notices = new ArrayList<>();
            for (ExamApplyItemDto itemDto : applyDto.getItems()) {
                int amount2 = (itemDto.getAmount() != null) ? itemDto.getAmount() : 1;
                itemNames.append("；" + itemDto.getItemName());
                itemCodes3.append("," + itemDto.getItemCode());
                itemFlags.append("," + itemDto.getFlags());
                if (StringUtils.isNotBlank(itemDto.getExamSubClass())) {
                    examSubClass.append("；" + itemDto.getExamSubClass());
                }
                if (amount2 > 1) {
                    itemNames.append(" 00d7" + amount2);
                }
                if (StringUtils.isNotBlank(itemDto.getOrgansFlag())) {
                    applyDto.setOrgansFlag(itemDto.getOrgansFlag());
                }
                if (StringUtils.isNotBlank(itemDto.getNotice())) {
                    String[] split;
                    String[] array = split = itemDto.getNotice().split("\\|");
                    for (String n : split) {
                        if (!notices.contains(n)) {
                            notices.add(n);
                        }
                    }
                }
                ExamApplyOrganDto examApplyOrganDto = new ExamApplyOrganDto();
                examApplyOrganDto.setApplyNo(itemDto.getApplyNo());
                examApplyOrganDto.setItemNo(itemDto.getItemNo());
                List<ExamApplyOrganDto> organs = examApplyOrganService.selectList(examApplyOrganDto);
                if (organs != null && !organs.isEmpty()) {
                    for (ExamApplyOrgan organ : organs) {
                        itemDto.setOrganName(organ.getOrganName());
                        organNames.append("；" + organ.getOrganName());
                    }
                }
                itemDto.setIndolenceFlag("0");
                itemDto.setClamFlag("0");
                if (StringUtils.isNotBlank(applyDto.getFlags())) {
                    char[] flagsArr = applyDto.getFlags().toCharArray();
                    itemDto.setIndolenceFlag(String.valueOf(flagsArr[12]));
                    itemDto.setClamFlag(String.valueOf(flagsArr[15]));
                }
                if (StringUtils.isNotBlank(itemDto.getExamRequire()) && !examRequires.contains(itemDto.getExamRequire())) {
                    examRequires.add(itemDto.getExamRequire());
                }
            }
            List<String> applyNos = new ArrayList<String>();
            if (StringUtils.isNotBlank(applyDto.getMergeNo())) {
                List<String> mergeNoList = CommonUtil.split2List(applyDto.getMergeNo());
                if (mergeNoList != null && !mergeNoList.isEmpty()) {
                    for (String mergeNo2 : mergeNoList) {
                        String applyNo = mergeNo2.substring(0, mergeNo2.lastIndexOf("-"));
                        if (!applyNos.contains(applyNo)) {
                            applyNos.add(applyNo);
                        }
                    }
                }
            } else {
                applyNos.add(applyDto.getApplyNo());
            }
            applyDto.setApplyNos(applyNos);
            notices = CommonUtil.convertNotice(notices, applyDto.getPatientSource(), applyDto.getEndTime(), applyDto.getBirthDate());
            applyDto.setItemNotice(String.join(" ", notices));
            applyDto.setItemTaboo(String.join("<br/>", CommonUtil.convertTaboo(notices)));
            applyDto.setItemNameStr((itemNames.length() > 0) ? itemNames.substring(1) : "");
            applyDto.setItemCodeStr((itemCodes3.length() > 0) ? itemCodes3.substring(1) : "");
            applyDto.setItemFlagStr((itemFlags.length() > 0) ? itemFlags.substring(1) : "");
            applyDto.setExamSubClassStr((examSubClass.length() > 0) ? examSubClass.substring(1) : "");
            applyDto.setExamRequireStr(String.join("；", examRequires));
            applyDto.setOrganNameStr((organNames.length() > 0) ? organNames.substring(1) : "");
            applyDto.setIndolenceFlag("0");
            applyDto.setClamFlag("0");
            if (StringUtils.isNotBlank(applyDto.getFlags())) {
                char[] flagsArr2 = applyDto.getFlags().toCharArray();
                applyDto.setIndolenceFlag(String.valueOf(flagsArr2[12]));
                applyDto.setClamFlag(String.valueOf(flagsArr2[15]));
            }
        }
        return lsExamApplyDto;
    }

    public String getDrugTime(String queueName, String scheduleApm) {
        QueryWrapper<DictScheduleApm> query = new QueryWrapper();
        query.select(new String[]{"DRUG_TIME"});
        query.eq("QUEUE_NAME", queueName);
        query.eq("SCHEDULE_APM", scheduleApm);
        List<DictScheduleApm> list = dictScheduleApmMapper.selectList(query);
        String drugTime = "";
        if (list != null && list.size() > 0) {
            drugTime = list.get(0).getDrugTime();
        }
        return drugTime;
    }

    public String getTimeSignin(String queueName, String scheduleApm) {
        QueryWrapper<DictScheduleApm> query = new QueryWrapper();
        query.select(new String[]{"TIME_SIGNIN"});
        query.eq("QUEUE_NAME", queueName);
        query.eq("SCHEDULE_APM", scheduleApm);
        List<DictScheduleApm> list = (List<DictScheduleApm>) dictScheduleApmMapper.selectList(query);
        String timeSignin = "";
        if (list != null && list.size() > 0) {
            timeSignin = list.get(0).getTimeSignin();
        }
        return timeSignin;
    }

    /**
     * 获取患者的最后生理期时间
     *
     * @param sickId
     * @return
     */
    public String getLastMensesDate(String sickId) {
        QueryWrapper<ExamApply> examApplyQuery = new QueryWrapper<>();
        examApplyQuery.select("LAST_MENSES_DATE");
        examApplyQuery.eq("SICK_ID", sickId);
        examApplyQuery.ge("REQ_DATE", DateUtil.date2Str(DateUtil.dateAdd(new Date(), -30), DateUtil.FORMAT_DATE));
        examApplyQuery.isNotNull("LAST_MENSES_DATE");
        examApplyQuery.orderByDesc("REQ_DATE");

        List<ExamApply> list = examApplyMapper.selectList(examApplyQuery);
        String lastMensesDate = "";
        if (!CollectionUtils.isEmpty(list)) {
            lastMensesDate = list.get(0).getLastMensesDate();
        }
        if (StringUtils.isBlank(lastMensesDate)) {
            QueryWrapper<ExamApplyPatient> examPatientQuery = new QueryWrapper<>();
            examPatientQuery.eq("SICK_ID", sickId);
            List<ExamApplyPatient> patientList = examApplyPatientMapper.selectList(examPatientQuery);
            if (patientList != null && patientList.size() > 0) {
                lastMensesDate = patientList.get(0).getLastMensesDate();
            } else {
                QueryWrapper<ExamPatient> examPatientQw = new QueryWrapper<>();
                examPatientQw.eq("SICK_ID", sickId);
                List<ExamPatient> patients = examPatientMapper.selectList(examPatientQw);
                if (patients != null && patients.size() > 0) {
                    lastMensesDate = patients.get(0).getLastMensesDate();
                }
            }
        }
        return lastMensesDate;
    }

    public List<DictCommonUse> findReminderList(String type, String examClass, String reserve1) {
        DictCommonUseDto dto = new DictCommonUseDto();
        dto.setName(type);
        dto.setExamClass(examClass);
        dto.setReserve1(reserve1);
        return dictCommonUseService.getList(dto);
    }

    /**
     * 取消预约是否释放号源
     * true 不释放
     * false 释放
     *
     * @param examClass
     * @return
     */
    public boolean isCancelNoFreeConfig(String examClass) {
        boolean isOrgansRecycle = false;
        if (StringUtils.isNotBlank(examClass)) {
            String noFreeSourceByCancel = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.NO_FREE_SOURCE_BY_CANCEL.getKey());
            if (StringUtils.isNotBlank(noFreeSourceByCancel)) {
                List<ConfigDto.NoFreeSourceByCancel> noFreeSourceByCancelList = JsonUtil.toList(noFreeSourceByCancel, ConfigDto.NoFreeSourceByCancel.class);
                if (CollectionUtils.isNotEmpty(noFreeSourceByCancelList)) {
                    for (ConfigDto.NoFreeSourceByCancel list : noFreeSourceByCancelList) {
                        if (list.getExamClass().contains(examClass)) {
                            isOrgansRecycle = true;
                            break;
                        }
                    }
                }
            }
        }
        return isOrgansRecycle;
    }

    /**
     * 取消预约 释放号源
     *
     * @param dto
     * @param isExamClass4Organ
     * @return
     */
    @Override
    public int cancelScheduleInfo(ExamApplyDto dto, boolean isExamClass4Organ) {
        int n = 0;
        ExamScheduleDto scheduleDto = new ExamScheduleDto();
        scheduleDto.setScheduledId(dto.getScheduledId());
        scheduleDto.setScheduledDate(dto.getScheduleDate());
        // 获取预约信息
        List<ExamSchedule> examList = examScheduleService.selectList(scheduleDto);
        if (CollectionUtils.isEmpty(examList)) {
            return n;
        }
        String apmCode = examList.get(0).getApmCode();
        if (StringUtils.isBlank(apmCode)) {
            return 1;
        }
        boolean isOvertimeReport = false;
//        if (StringUtils.isBlank(dto.getScheduleStatus()) || "08".equals(dto.getScheduleStatus())) {
//        }
        List<String> applyNos = new ArrayList<>();
        List<String> mergeNoList = CommonUtil.split2List(dto.getMergeNo());
        if (StringUtils.isBlank(dto.getMergeNo())) {
            ExamScheduleItem it = new ExamScheduleItem();
            it.setScheduledId(dto.getScheduledId());
            it.setApplyNo(dto.getApplyNo());
            List<ExamScheduleItem> items = examScheduleItemServiceImpl.getItemList(it);
            for (ExamScheduleItem item : items) {
                mergeNoList.add(item.getApplyNo() + "-" + item.getItemNo());
            }
            applyNos.add(dto.getApplyNo());
        } else {
            applyNos = CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
        }
        // 生成id
        String scheduledId = PKGeneratorSingle.getInstance().nextPKStr();
        for (String mergeNos : mergeNoList) {
            int idx = mergeNos.lastIndexOf("-");
            String applyno = mergeNos.substring(0, idx);
            String itemNo = mergeNos.substring(idx + 1);
            if (isOvertimeReport) {
                // 预约项目明细
                UpdateWrapper<ExamScheduleItem> update = new UpdateWrapper<>();
                update.eq("APPLY_NO", applyno);
                update.eq("ITEM_NO", itemNo);
                update.eq("SCHEDULED_ID", dto.getScheduledId());
                ExamScheduleItem esi = new ExamScheduleItem();
                esi.setScheduledId(scheduledId);
                // 更新成新的id
                n = examScheduleItemMapper.update(esi, update);

                // 预约项目主表
                QueryWrapper<ExamSchedule> qw = new QueryWrapper<>();
                qw.eq("SCHEDULED_ID", dto.getScheduledId());
                qw.ne("SCHEDULE_STATUS", "00");
                List<ExamSchedule> esList = examScheduleMapper.selectList(qw);

                ExamSchedule eschedule = esList.get(0);
                eschedule.setScheduleStatus("00");
                eschedule.setScheduledId(scheduledId);
                // 重新插入新的预约记录
                examScheduleMapper.insert(eschedule);
            } else {
                Map<String, Object> map = new HashMap<>();
                map.put("SCHEDULED_ID", dto.getScheduledId());
                map.put("APPLY_NO", applyno);
                map.put("ITEM_NO", itemNo);
                n = examScheduleItemMapper.deleteByMap(map);
                log.info("删除item 预约id：" + dto.getScheduledId() + ",申请单号：" + applyno + ",项目编码：" + itemNo);
            }
        }
        ExamApplyDto ea = new ExamApplyDto();
        ea.setApplyNo(dto.getApplyNo());
        ea.setApmCode(apmCode);
        ea.setMergeNoList(mergeNoList);
        ea.setScheduledId(dto.getScheduledId());
        ea.setExamClass(dto.getExamClass());
        ea.setScheduleDate(dto.getScheduleDate());
        ea.setOrgans(examList.get(0).getOrgans());
        ea.setNextApmRatio(examList.get(0).getNextApmRatio());
        ea.setRegularIdList(CommonUtil.split2List(examList.get(0).getRegularId()));
        ea.setReqCount(dto.getReqCount());
        ea.setIsExamClass4Organ(isExamClass4Organ);
        if (StringUtils.isBlank(dto.getType())) {
            // 取消预约时段-释放号源
            cancelScheduleApm(ea);
        }
        dto.setUpdateApm(ea);
        return n;
    }

    /**
     * 取消预约时段-释放号源
     *
     * @param dto
     */
    public void cancelScheduleApm(ExamApplyDto dto) {
        boolean isOvertimeReport = false;
        boolean isDeleteAll = false;
        // 获取预约项目的条目数量
        int count = examScheduleItemServiceImpl.getExamScheduleItemSelectCount(dto.getScheduledId());
        if (count == 0 && !isOvertimeReport) {
            Map<String, Object> map = new HashMap<>();
            map.put("SCHEDULED_ID", dto.getScheduledId());
            examScheduleMapper.deleteByMap(map);
            isDeleteAll = true;
        }
        boolean isCancelPower = configServiceImpl.getNoFreeSourceByCancel(dto.getExamClass(), dto.getScheduleDate());
        double cancelOrgans = (dto.getOrgans() == null) ? 0.0 : dto.getOrgans();
        String cancelNextApmRatio = dto.getNextApmRatio();
        String regularId = subtracDictScheduleApmRegular(dto.getIsExamClass4Organ(), dto.getRegularIdList(), dto.getMergeNoList(), dto.getScheduleDate(), isDeleteAll);
        if (isDeleteAll) {
            ExamScheduleApm examScheduleApm = new ExamScheduleApm();
            examScheduleApm.setScheduleDate(dto.getScheduleDate());
            examScheduleApm.setApmCode(dto.getApmCode());
            // 按项目预约量系数占号
            if (dto.getIsExamClass4Organ()) {
                if (StringUtils.isNotBlank(cancelNextApmRatio)) {
                    String[] nextApmRatioArr = cancelNextApmRatio.split("\\|");
                    for (String nextApmRatio : nextApmRatioArr) {
                        String[] apmArr = nextApmRatio.split("=");
                        cancelOrgans -= Double.parseDouble(apmArr[1]);
                        ExamScheduleApm esa = new ExamScheduleApm();
                        esa.setScheduleDate(dto.getScheduleDate());
                        esa.setApmCode(apmArr[0]);
                        // 按项目预约量系数占号
                        esa.setOrgans(Double.parseDouble(apmArr[1]));
                        lockScheduleApm(true, esa, isCancelPower, dto.getIsExamClass4Organ());
                    }
                }
                examScheduleApm.setOrgans(cancelOrgans);
            }
            examScheduleApm.setCount(1);
            lockScheduleApm(true, examScheduleApm, isCancelPower, dto.getIsExamClass4Organ());
        }
        if (!isDeleteAll) {
            if (dto.getIsExamClass4Organ()) {
                double nextOrganTotal = 0.0;
                String[] apmRatioArr = new String[0];
                double nextCancelOrgans = dto.getReqCount();
                boolean isPass = true;
                StringBuffer bf = new StringBuffer();
                if (StringUtils.isNotBlank(cancelNextApmRatio)) {
                    boolean isEnough = false;
                    String[] nextApmRatioArr2 = CommonUtil.reverseArray(cancelNextApmRatio.split("\\|"));
                    apmRatioArr = new String[nextApmRatioArr2.length];
                    for (int j = 0; j < nextApmRatioArr2.length; ++j) {
                        String[] apmArr2 = nextApmRatioArr2[j].split("=");
                        if (isEnough) {
                            apmRatioArr[j] = nextApmRatioArr2[j];
                        } else {
                            nextOrganTotal = BigDecimalUtil.add(nextOrganTotal, Double.parseDouble(apmArr2[1]));
                            if (j > 0) {
                                nextCancelOrgans = Math.abs(nextCancelOrgans);
                            }
                            nextCancelOrgans = BigDecimalUtil.subtract(Double.parseDouble(apmArr2[1]), nextCancelOrgans);
                            ExamScheduleApm examScheduleApm2 = new ExamScheduleApm();
                            examScheduleApm2.setScheduleDate(dto.getScheduleDate());
                            examScheduleApm2.setApmCode(apmArr2[0]);
                            if (j == 0 && dto.getReqCount() <= Double.parseDouble(apmArr2[1])) {
                                examScheduleApm2.setOrgans(dto.getReqCount());
                            } else if (nextCancelOrgans <= 0.0) {
                                examScheduleApm2.setOrgans(Double.parseDouble(apmArr2[1]));
                            } else {
                                double a = BigDecimalUtil.subtract(Double.parseDouble(apmArr2[1]), nextCancelOrgans);
                                examScheduleApm2.setOrgans(a);
                            }
                            lockScheduleApm(true, examScheduleApm2, isCancelPower, dto.getIsExamClass4Organ());
                            if (nextCancelOrgans > 0.0) {
                                apmRatioArr[j] = apmArr2[0] + "=" + nextCancelOrgans;
                            }
                            if (nextCancelOrgans >= 0.0) {
                                isEnough = true;
                            }
                        }
                    }
                    String[] reverseArray;
                    apmRatioArr = (reverseArray = CommonUtil.reverseArray(apmRatioArr));
                    for (String str : reverseArray) {
                        if (str != null) {
                            bf.append("|" + str);
                        }
                    }
                    nextOrganTotal = BigDecimalUtil.subtract(nextOrganTotal, dto.getReqCount());
                    if (nextOrganTotal >= 0.0) {
                        isPass = false;
                    }
                }
                if (isPass) {
                    ExamScheduleApm examScheduleApm3 = new ExamScheduleApm();
                    examScheduleApm3.setScheduleDate(dto.getScheduleDate());
                    examScheduleApm3.setApmCode(dto.getApmCode());
                    double reqCount = dto.getReqCount();
                    if (reqCount != 0.0) {
                        if (nextOrganTotal < 0.0) {
                            reqCount = Math.abs(nextOrganTotal);
                        }
                        examScheduleApm3.setOrgans(reqCount);
                        if (nextOrganTotal == 0.0 && BigDecimalUtil.subtract(cancelOrgans, reqCount) == 0.0) {
                            examScheduleApm3.setCount(1);
                        }
                        lockScheduleApm(true, examScheduleApm3, isCancelPower, dto.getIsExamClass4Organ());
                    }
                }
                UpdateWrapper<ExamSchedule> update = new UpdateWrapper<>();
                update.eq("SCHEDULED_ID", dto.getScheduledId());
                ExamSchedule es = new ExamSchedule();
                update.set(StringUtils.isBlank(bf.toString()), "NEXT_APM_RATIO", "");
                update.set(StringUtils.isBlank(regularId), "REGULAR_ID", "");
                double organs = BigDecimalUtil.subtract(cancelOrgans, dto.getReqCount());
                es.setOrgans(organs);
                es.setNextApmRatio(StringUtils.isNotBlank(bf.toString()) ? bf.substring(1) : "");
                es.setRegularId(regularId);
                examScheduleMapper.update(es, update);
                if (organs <= 0.0) {
                    String customPhone = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CUSTOM_PHONE.getKey());
                    ExamSmsNotice esn = new ExamSmsNotice();
                    esn.setSmsNo(dictSerialService.getSerialId("SMS_NO"));
                    esn.setApplyNo(dto.getApplyNo());
                    esn.setSmsType("3");
                    String content = "预约ID：" + dto.getScheduledId() + "，预约日期：" + dto.getScheduleDate() + "，apmCpde：" + dto.getApmCode() + "号源修改：" + organs + "发现异常，请检查";
                    esn.setSmsContent(content);
                    esn.setPhoneNumber(customPhone);
                    esn.setCreateDate(DateUtil.getCurrDateStr());
                    esn.setCreateTime(DateUtil.getCurrentTime());
                    examSmsNoticeService.insert(esn);
                }
            }
            if (!dto.getIsExamClass4Organ()) {
                UpdateWrapper<ExamSchedule> update2 = new UpdateWrapper<>();
                update2.eq("SCHEDULED_ID", dto.getScheduledId());
                update2.set(StringUtils.isBlank(regularId), "REGULAR_ID", "");
                ExamSchedule es2 = new ExamSchedule();
                es2.setRegularId(regularId);
                examScheduleMapper.update(es2, update2);
            }
        }
    }

    public Double getOrgansReqCount(ExamApplyDto ea) {
        boolean isExamClass4Organ = configServiceImpl.getOrganExamClassList().contains(ea.getExamClass());
        if (!isExamClass4Organ) {
            return null;
        }
        ExamApplyDto ead = new ExamApplyDto();
        ead.setScheduledId(ea.getScheduledId());
        List<ExamScheduleItem> examlist = examScheduleItemMapper.getExamScheduleItemForUnequal(ead);
        if (examlist.size() == 0) {
            return null;
        }
        if (StringUtils.isBlank(ea.getMergeNo())) {
            return null;
        }
        String[] mergeNoArray = ea.getMergeNo().split(",");
        if (mergeNoArray.length == examlist.size()) {
            return null;
        }
        StringBuffer mergeNoStr = new StringBuffer();
        for (ExamScheduleItem itemList : examlist) {
            mergeNoStr.append("," + itemList.getApplyNo() + "-" + itemList.getItemNo());
        }
        List<ExamApplyItemDto> itemDtoList = getExamApplyItem(mergeNoStr.substring(1), ea);
        QueryWrapper<ExamSchedule> qw = new QueryWrapper<>();
        qw.eq("SCHEDULED_ID", ea.getScheduledId());
        qw.ne("SCHEDULE_STATUS", "00");
        ExamSchedule es = (ExamSchedule) examScheduleMapper.selectOne(qw);
        double reqRatio = es.getOrgans();
        List<String> applyNos = new ArrayList<String>();
        for (String mergeNo : mergeNoArray) {
            int idx = mergeNo.lastIndexOf("-");
            applyNos.add(mergeNo.substring(0, idx) + Integer.parseInt(mergeNo.substring(idx + 1, mergeNo.length())));
        }
        Iterator<ExamApplyItemDto> it = itemDtoList.iterator();
        while (it.hasNext()) {
            ExamApplyItemDto items = it.next();
            String item = items.getApplyNo() + items.getItemNo();
            if (applyNos.contains(item)) {
                it.remove();
            } else {
                items.setOrgansFlag(null);
            }
        }
        double reqCountOther = reqRatio;
        if (itemDtoList != null && itemDtoList.size() > 0) {
            double countOther = getReqOrganByItems(itemDtoList);
            reqCountOther = reqRatio - countOther;
        }
        return reqCountOther;
    }

    /**
     * @param items
     * @return
     * @description 获取占号量
     * @author ryan.li
     * @date 2022/10/21 17:38
     */
    @Override
    public double getReqOrganByItems(List<ExamApplyItemDto> items) {
        BigDecimal reqRatio = new BigDecimal(0);
        if (CollectionUtils.isNotEmpty(items)) {
            Map<String, Object> map = new HashMap<>();
            String examClass = items.get(0).getExamClass();
            map.put("examClass", examClass);
            map.put("groupType", ConstantsUtil.GroupType.THREE.getKey());
            // 检查类别和分组类型 组合系数
            int groupCount = dictItemGroupMapper.existsGroup(map);
            boolean existsGroup = items.size() > 1 && groupCount > 0;

            if (existsGroup) {
                String mergeFullMatchExamClass = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.MERGE_FULL_MATCH_EXAM_CLASS.getKey());
                String mergePartMatchExamClass = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.MERGE_PART_MATCH_EXAM_CLASS.getKey());
                List<String> itemCodes = new ArrayList<>();
                for (ExamApplyItem item : items) {
                    itemCodes.add(item.getItemCode());
                }
                map.put("itemCodeList", itemCodes);
                List<DictItemGroupDto> itemGroupList = dictItemGroupMapper.existsGroupForNoSame(map);
                List<Map<String, Object>> groups = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(itemGroupList)) {
                    for (DictItemGroupDto examItemGroup : itemGroupList) {
                        if (examItemGroup.getGroupCount() >= 2 && examItemGroup.getGroupCount() >= itemCodes.size()) {
                            if (mergeFullMatchExamClass.contains(examClass)) {
                                int itemCount = Integer.parseInt(examItemGroup.getItemCount());
                                if (itemCodes.size() != itemCount) {
                                    continue;
                                }
                                if (examItemGroup.getGroupCount() != itemCount) {
                                    continue;
                                }
                            }
                            Map<String, Object> map_groups = new HashMap<>();
                            map_groups.put("groupCode", examItemGroup.getGroupCode());
                            map_groups.put("groupRatio", examItemGroup.getGroupRatio());
                            groups.add(map_groups);
                            break;
                        }
                        if (examItemGroup.getGroupCount() >= 2 && mergePartMatchExamClass.contains(examClass)) {
                            Map<String, Object> map_groups = new HashMap<>();
                            map_groups.put("groupCode", examItemGroup.getGroupCode());
                            map_groups.put("groupRatio", examItemGroup.getGroupRatio());
                            groups.add(map_groups);
                            break;
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(groups)) {
                    map.put("itemCodeList", null);
                    Map<String, String> mapFlag = new HashMap<>();
                    for (ExamApplyItemDto itemDto : items) {
                        for (Map<String, Object> group : groups) {
                            String groupCode = group.get("groupCode").toString();
                            String groupRatio = (group.get("groupRatio") != null) ? group.get("groupRatio").toString() : "1";
                            DictItemGroupDto itemGroup = new DictItemGroupDto();
                            itemGroup.setItemCode(itemDto.getItemCode());
                            itemGroup.setExamClass(examClass);
                            itemGroup.setGroupCode(groupCode);
                            itemGroup.setGroupType(ConstantsUtil.GroupType.THREE.getKey());
                            List<DictItemGroupDto> examItemGroupList = dictItemGroupMapper.getGroupList(itemGroup);
                            if (examItemGroupList != null && examItemGroupList.size() > 0) {
                                DictItemGroupDto examItemGroup2 = examItemGroupList.get(0);
                                if (!groupCode.equals(examItemGroup2.getGroupCode())) {
                                    continue;
                                }
                                itemDto.setOrgansFlag("1");
                                if (mapFlag.containsKey(groupCode)) {
                                    continue;
                                }
                                mapFlag.put(groupCode, groupRatio);
                            }
                        }
                    }
                    for (String key : mapFlag.keySet()) {
                        String groupRatio2 = (mapFlag.get(key) != null) ? mapFlag.get(key) : "1";
                        BigDecimal ratioBG = new BigDecimal(groupRatio2);
                        reqRatio = reqRatio.add(ratioBG);
                    }
                }
            }

            for (ExamApplyItemDto itemDto : items) {
                int amount = (itemDto.getAmount() != null) ? itemDto.getAmount() : 1;
                if (StringUtils.isBlank(itemDto.getOrgansFlag())) {
                    double ratio = itemDto.getOrgans() * amount;
                    BigDecimal ratioBG = new BigDecimal(Double.toString(ratio));
                    reqRatio = reqRatio.add(ratioBG);
                }
            }
        }
        return reqRatio.doubleValue();
    }

    /**
     * 是否还有其他的时段可以预约
     *
     * @param examScheduleDto
     * @param isSchedulePlan
     * @return
     */
    public boolean hasOtherSchedule(ExamScheduleDto examScheduleDto, boolean isSchedulePlan) {
        List<ExamSchedule> list;
        if (isSchedulePlan) {
            list = examScheduleMapper.getExamScheduleOther4Plan(examScheduleDto);
        } else {
            list = examScheduleMapper.getExamScheduleOther(examScheduleDto);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            // String[] arr = examScheduleDto.getScheduleApm().replace("-", "~").split("~");
            String[] arr = examScheduleDto.getScheduleApm().split("-");
            if (arr.length != 2) {
                return false;
            }
            int st = Integer.parseInt(arr[0].replace(":", ""));
            int et = Integer.parseInt(arr[1].replace(":", ""));
            if (!"00:00".equals(arr[0]) && "00:00".equals(arr[1])) {
                et = 2400;
            }
            // 已预约的日期时间
            String scheduleDateTimeStart = examScheduleDto.getScheduledDate() + " " + arr[0];
            for (ExamSchedule examSchedule : list) {
                if (StringUtils.isNotBlank(examSchedule.getScheduleApm())) {
                    //String[] apmTime = examSchedule.getScheduleApm().replace("-", "~").split("~");
                    String[] apmTime = examSchedule.getScheduleApm().split("-");
                    if (apmTime.length != 2) {
                        continue;
                    }
                    if (!apmTime[0].contains(":") || !apmTime[1].contains(":")) {
                        continue;
                    }
                    int startTime = Integer.valueOf(apmTime[0].replace(":", ""));
                    int endTime = Integer.valueOf(apmTime[1].replace(":", ""));
                    if (!"00:00".equals(apmTime[0]) && "00:00".equals(apmTime[1])) {
                        endTime = 2400;
                    }
                    if ((st > startTime && st < endTime) || (et > startTime && et < endTime) || (st <= startTime && et >= endTime)) {
                        return true;
                    }
                    int intervalTime = 0;

                    String scheduleDateTimeCurrStart = examScheduleDto.getScheduledDate() + " " + apmTime[0];
                    // 两个时间的差值
                    int intervalMinus = DateUtil.getIntervalMinus(scheduleDateTimeCurrStart, scheduleDateTimeStart);
                    if (intervalTime > intervalMinus) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public Map<String, String> getAdvanceTimeAndReqReachTime(String queueName, String scheduleDate, String scheduleApm, String examClass, String examApm) {
        String advanceTime = "";
        String reqReachTime = "";
        String reqReachTime_temp = "";
        String timeSignin = getTimeSignin(queueName, scheduleApm);
        if (StringUtils.isNotBlank(timeSignin) && StringUtils.isNotBlank(timeSignin.trim())) {
            reqReachTime_temp = scheduleDate + " " + timeSignin.trim();
        }
        if (StringUtils.isNotBlank(examApm)) {
            scheduleApm = examApm;
        }
        String[] arr = scheduleApm.replace("-", "~").split("~");
        String timeStart = arr[0] + ":00";
        String timeEnd = arr[1] + ":00";
        String advanceTimeType = "1";
        if (StringUtils.isNotBlank(timeStart) && StringUtils.isNotBlank(timeEnd)) {
            advanceTime = scheduleDate + " " + timeStart;
            reqReachTime = scheduleDate + " " + timeEnd;
            String duration = "";
            if (StringUtils.isNotBlank(duration)) {
                String[] d = duration.split("\\|");
                int m = Integer.parseInt(d[0]);
                int n = Integer.parseInt(d[1]);
                if ("1".equals(advanceTimeType)) {
                    if (m > 0) {
                        String et = timeStart.substring(0, timeStart.lastIndexOf(":"));
                        String st = DateUtil.addMinutes1(scheduleDate + " " + et, -m);
                        advanceTime = st + "~" + et;
                    }
                } else if ("2".equals(advanceTimeType)) {
                    if (StringUtils.isNotBlank(timeSignin) && StringUtils.isNotBlank(timeSignin.trim())) {
                        timeEnd = timeSignin.trim();
                    }
                    String st2 = timeStart.substring(0, timeStart.lastIndexOf(":"));
                    st2 = DateUtil.addMinutes1(scheduleDate + " " + st2, -m);
                    String et2 = timeEnd.substring(0, timeEnd.lastIndexOf(":"));
                    if (StringUtils.isBlank(timeSignin) || StringUtils.isBlank(timeSignin.trim())) {
                        et2 = DateUtil.addMinutes2(et2, -n);
                    }
                    advanceTime = st2 + "~" + et2;
                } else {
                    advanceTime = DateUtil.addMinutes(advanceTime, -m);
                }
                reqReachTime = DateUtil.addMinutes(reqReachTime, -n);
            }
            if (!advanceTime.contains("~")) {
                advanceTime = advanceTime.substring(0, advanceTime.lastIndexOf(":")) + "前";
            }
        } else if ("2".equals(advanceTimeType)) {
            if (StringUtils.isNotBlank(timeSignin) && StringUtils.isNotBlank(timeSignin.trim())) {
                timeEnd = timeSignin.trim();
            }
            String st3 = timeStart.substring(0, timeStart.lastIndexOf(":"));
            String et3 = timeEnd.substring(0, timeEnd.lastIndexOf(":"));
            advanceTime = scheduleDate + " " + st3 + "~" + et3;
        }
        if (StringUtils.isNotBlank(reqReachTime_temp)) {
            reqReachTime = reqReachTime_temp;
        }
        Map<String, String> map = new HashMap<>();
        map.put("advanceTime", advanceTime);
        map.put("reqReachTime", reqReachTime);
        return map;
    }

    /**
     * @param itemsAll
     * @return
     * @description 查找有孕期限制的检查项目
     * @author ryan.li
     * @date 2022/10/18 10:39
     */
    public List<ExamApplyItemDto> getGestationalItems(List<ExamApplyItemDto> itemsAll) {
        List<ExamApplyItemDto> items = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(itemsAll)) {
            items = itemsAll.stream().filter(eai -> StringUtils.isNotBlank(eai.getGestinfoDayscope())).collect(Collectors.toList());
        }
        return items;
    }

    public Boolean isGestationalDate(String date, String lastMensesDate, List<ExamApplyItemDto> items) {
        /**
         * 怀孕天数
         */
        int days = DateUtil.getIntervalDays(lastMensesDate, date);
        int minLimit = -10000;
        int maxLimit = 10000;
        for (ExamApplyItemDto item : items) {
            String gestinfoDayscope = item.getGestinfoDayscope();
            if (StringUtils.isNotBlank(gestinfoDayscope)) {
                String[] arr = gestinfoDayscope.split("~");
                if (StringUtils.isNotBlank(arr[0])) {
                    int min = Integer.parseInt(arr[0]);
                    if (min > minLimit) {
                        minLimit = min;
                    }
                }
                if (StringUtils.isNotBlank(arr[1])) {
                    int max = Integer.parseInt(arr[1]);
                    if (max < maxLimit) {
                        maxLimit = max;
                    }
                }
            }
        }
        if (minLimit != -10000 && maxLimit != 10000) {
            if (days < minLimit) {
                return false;
            }
            if (days > maxLimit) {
                return false;
            }
        }
        return true;
    }

    public Map<String, String> getApplyGestDate(String lastMensesDate, List<ExamApplyItemDto> items) {
        int minLimit = -10000;
        int maxLimit = 10000;
        for (int i = 0; i < items.size(); ++i) {
            String gestinfoDayscope = items.get(i).getGestDays();
            if (StringUtils.isNotBlank(gestinfoDayscope)) {
                String[] arr = gestinfoDayscope.split("~");
                if (StringUtils.isNotBlank(arr[0])) {
                    int min = Integer.parseInt(arr[0]);
                    if (min > minLimit) {
                        minLimit = min;
                    }
                }
                if (StringUtils.isNotBlank(arr[1])) {
                    int max = Integer.parseInt(arr[1]);
                    if (max < maxLimit) {
                        maxLimit = max;
                    }
                }
            }
        }
        Map<String, String> map = new HashMap<String, String>();
        if (minLimit != -10000 && maxLimit != 10000) {
            map.put("startDate", DateUtil.addDays2(lastMensesDate, minLimit));
            map.put("endDate", DateUtil.addDays2(lastMensesDate, maxLimit));
            return map;
        }
        return null;
    }

    /**
     * 根据预约日期过滤可用的检查队列
     * 提前预约天数和预约开放天数限制
     *
     * @param queues            所有的队列列表
     * @param date              预约日期
     * @param patientSourceDays 患者来源天数
     * @return 符合的预约队列列表
     */
    @Override
    public List<DictExamQueueDto> getQueueListByDate(List<DictExamQueueDto> queues, String date, Integer patientSourceDays) {
        List<DictExamQueueDto> list = new ArrayList<>();
        if (queues != null) {
            int queueExpireDays = 0;
            for (DictExamQueueDto queue : queues) {
                // 提前预约月天数
                Integer beginDays = queue.getBeginDays();
                // 开放预约天数
                Integer expireDays = queue.getExpireDays();

                if (expireDays == null) {
                    expireDays = patientSourceDays;
                }
                // 队列是否可以预约
                boolean enableSchedule = true;
                if (beginDays != null && beginDays != 0) {
                    String beginDate = DateUtil.addDays(beginDays);
                    // 预约日期小于最早开始预约时间 不能预约
                    if (date.compareTo(beginDate) < 0) {
                        enableSchedule = false;
                    }
                }
                // 验证最晚预约日期
                if (enableSchedule && expireDays != null && expireDays >= 0) {
                    if (beginDays != null) {
                        expireDays += beginDays;
                        if (queueExpireDays < expireDays) {
                            // 开放预约天数 = 队列开放预约天数 + 队列提前预约天数
                            queueExpireDays = expireDays;
                        }
                    }
                    // 开放预约结束日期
                    String expireDate = DateUtil.addDays(expireDays - 1);
                    if (date.compareTo(expireDate) > 0) {
                        enableSchedule = false;
                    }
                }
                if (enableSchedule) {
                    list.add(queue);
                }
            }
        }
        return list;
    }

    /**
     * 判断日期是否可以预约-号是否满
     *
     * @param queues
     * @param date
     * @param examApply
     * @return
     */
    public ExamApplyDto getScheduleDate(List<DictExamQueueDto> queues, String date, ExamApplyDto examApply) {
        try {
            DictScheduleApmDto dictScheduleApmDto = new DictScheduleApmDto();
            String beginTime = "";
            boolean isGreenChannel = StringUtils.isNotBlank(examApply.getIsGreenChannel());
            if (isGreenChannel) {
                dictScheduleApmDto.setIsGreenChannel(examApply.getIsGreenChannel());
            } else {
                if (examApply.getLimitScheduleDate() != null && examApply.getLimitScheduleDate().contains(date)) {
                    return null;
                }
                int itemBeginTime = (examApply.getBeginTime() == null) ? 0 : examApply.getBeginTime();
                if (itemBeginTime != 0) {
                    Map<String, Object> map = DateUtil.getAfterTime(itemBeginTime);
                    String beginDate = map.get("date") + "";
                    if (date.compareTo(beginDate) < 0) {
                        return null;
                    }
                    if (date.compareTo(beginDate) == 0) {
                        beginTime = map.get("time") + "";
                    }
                }
                int clamBeforesTime = (examApply.getClamBeforesTime() == null) ? 0 : examApply.getClamBeforesTime();
                if (clamBeforesTime != 0) {
                    Map<String, Object> map2 = DateUtil.getAfterTime(clamBeforesTime);
                    String beginDate2 = map2.get("date") + "";
                    if (date.compareTo(beginDate2) < 0) {
                        return null;
                    }
                    if (date.compareTo(beginDate2) == 0 && clamBeforesTime > itemBeginTime) {
                        beginTime = map2.get("time") + "";
                    }
                }
            }
            if (date.compareTo(DateUtil.getCurrDateStr()) == 0 || StringUtils.isNotBlank(beginTime)) {
                String currTime = DateUtil.getCurrentTime();
                if (StringUtils.isNotBlank(beginTime)) {
                    currTime = beginTime;
                }
                dictScheduleApmDto.setCurrTime(currTime);
            }
            dictScheduleApmDto.setScheduleDate(date);
            dictScheduleApmDto.setWeekDate(DateUtil.getWeek(date));
            dictScheduleApmDto.setQueues(queues);
            dictScheduleApmDto.setStaffName(examApply.getStaffName());
            // 获取日期所有可用时段列表 key: getQueueName() + "=" + dsa.getTimeStart() + dsa.getDateStart() + dsa.getDateEnd()
            Map<String, DictScheduleApmDto> apmMap = getScheduleApmMap(dictScheduleApmDto);
            // log.info("getScheduleDate:apmMap:{}", JacksonUtil.toJsonString(apmMap));
            // List<String> apmCodes = new ArrayList<>();
            // 是否可以用 0 已满 1可用 2 停用
            String enabled = "2";
            String earliestTime = "";
            String time = "00:00:00";
            String remainCountStr = "停";
            double organsTotal = 0.0;
            // 时段是否可用
            boolean apmIsEnable = false;
            boolean isFirst = true;
            // 规则是否匹配
            // boolean isRuleMate = false;
            // 申请单需要占用的号源系数
            double reqCount = examApply.getReqCount();
            // 可以预约的队列列表
            List<String> queueNames = new ArrayList<>();

            // 日期剩余可预约数量
            double dayLeftCount = 0.0;
            //
            List<String> enables = new ArrayList<>();

            for (String key : apmMap.keySet()) {
                DictScheduleApmDto scheduleApmDto = apmMap.get(key);
                log.info("getScheduleDate:apmCode:{},regularId:{}", key, JacksonUtil.toJsonString(scheduleApmDto.getRegularIdInfo()));
                // 停用的直接返回
                if ("1".equals(scheduleApmDto.getStopFlag())) {
                    enables.add("2");
                    continue;
                }
                // apmCodes.addAll(scheduleApmDto.getApmCodes());
                apmIsEnable = true;
                // 非绿色通道-需要判断预约规则和预约数量规则
                if (!isGreenChannel) {
                    // 申请单规则是否可用 缓存结果
                    Boolean cacheBool = null;
                    String keyId = "";
                    if (StringUtils.isNotBlank(examApply.getMergeNo())) {
                        keyId = examApply.getMergeNo() + scheduleApmDto.getRegularIdInfo() + examApply.getTerminalType();
                        cacheBool = (Boolean) EhCacheUtil.get(ConstantsUtil.EhCacheName.ruleResultCache.name(), keyId);
                    }
                    if (cacheBool != null) {
                        apmIsEnable = cacheBool;
                    } else {
                        // 获取申请单是否可用这个时段
                        apmIsEnable = isEnabledScheduleApm(scheduleApmDto, examApply, date);
                        if (StringUtils.isNotBlank(keyId)) {
                            EhCacheUtil.put(ConstantsUtil.EhCacheName.ruleResultCache.name(), keyId, apmIsEnable);
                        }
                    }
                    if (apmIsEnable) {
                        // isRuleMate = true;
                        // 判断时段数量规则是否还有数量可以进行预约
                        apmIsEnable = ruleEngineServiceImpl.quantityRuleJudge(examApply, scheduleApmDto, date);
                    }
                }
                // 时段不可以使用直接返回
                if (!apmIsEnable) {
                    continue;
                }
                double itemMaxLimit = (scheduleApmDto.getMaxLimit() != null) ? scheduleApmDto.getMaxLimit() : 0.0;
                // 获取已使用数量信息
                ExamScheduleApm apm = examScheduleApm(date, scheduleApmDto.getApmCodes(), examApply.getExamClass());
                int countRecycle = 0;
                double organsRecycle = 0.0;
                if (!examApply.getIsCancelPower()) {
                    countRecycle = ((apm.getCountRecycle() == null || apm.getCountRecycle() < 0) ? 0 : apm.getCountRecycle());
                    organsRecycle = ((apm.getOrgansRecycle() == null || apm.getOrgansRecycle() < 0.0) ? 0.0 : apm.getOrgansRecycle());
                }
                // 时段剩余号数
                double remainCount = 0d;
                // 时段循环号数
                double apmRecycle = 0d;
                if (examApply.getIsExamClass4Organ()) {
                    remainCount = BigDecimalUtil.subtract(BigDecimalUtil.subtract(itemMaxLimit, apm.getOrgans()), organsRecycle);
                    apmRecycle = BigDecimalUtil.add(apm.getOrgans(), organsRecycle);
                    double currentRemainCount = configServiceImpl.currentRemainCount(date, scheduleApmDto.getTimeStart(), scheduleApmDto.getTimeEnd(), itemMaxLimit, apmRecycle);
                    if (currentRemainCount >= 0.0 && remainCount > currentRemainCount) {
                        remainCount = currentRemainCount;
                    }
//                    if (remainCount <= 0.0) {
//                        continue;
//                    }
                    if (remainCount < reqCount) {
                        if (!isFirst) {
                            String timeEnd = DateUtil.addSecond(time, 1);
                            if (!timeEnd.equals(scheduleApmDto.getTimeStart())) {
                                organsTotal = 0.0;
                            }
                        }
                        time = scheduleApmDto.getTimeEnd();
                        isFirst = false;
                    }
                    if (CollectionUtils.isNotEmpty(queueNames)
                            && !queueNames.contains(scheduleApmDto.getQueueName())) {
                        organsTotal = 0.0;
                    }
                    queueNames.add(scheduleApmDto.getQueueName());
                    organsTotal = BigDecimalUtil.add(organsTotal, remainCount);
                    if (organsTotal < reqCount) {
                        continue;
                    }
                } else {
                    remainCount = BigDecimalUtil.subtract(BigDecimalUtil.subtract(itemMaxLimit, apm.getCount()), countRecycle);
                    apmRecycle = BigDecimalUtil.add(apm.getCount(), countRecycle);
                    double currentRemainCount = configServiceImpl.currentRemainCount(date, scheduleApmDto.getTimeStart(), scheduleApmDto.getTimeEnd(), itemMaxLimit, apmRecycle);
                    if (currentRemainCount >= 0.0 && remainCount > currentRemainCount) {
                        remainCount = currentRemainCount;
                    }
//                    if (remainCount < reqCount) {
//                        continue;
//                    }
                    //remainCountStr = "剩余" + ((remainCount > 0.0) ? (remainCount + "").replaceAll("\\.0", "") : "0") + "人";
                }
                enabled = "1";
                enables.add(enabled);
                if (StringUtils.isBlank(earliestTime)) {
                    earliestTime = scheduleApmDto.getTimeStart();
                }
                dayLeftCount += remainCount;
            }

            ExamApplyDto examApplyDto = new ExamApplyDto();
            if (StringUtils.isNotBlank(examApply.getLastMensesDate())) {
                int pregnantDays = DateUtil.getIntervalDays(examApply.getLastMensesDate(), date);
                int weeks = pregnantDays / 7;
                int days = pregnantDays % 7;
                String gestationalWeeks = weeks + "周";
                if (days > 0) {
                    gestationalWeeks = gestationalWeeks + days + "天";
                }
                examApplyDto.setGestationalWeeks(gestationalWeeks);
            }
            examApplyDto.setDate(date);
            // 只要有一个可以预约的时段，日期就可以用
            if (enables.contains("1")) {
                examApplyDto.setEnabled("1");
            }
            if (dayLeftCount <= 0) {
                remainCountStr = "满";
                examApplyDto.setEnabled("0");
            } else {
                remainCountStr = "剩余" + dayLeftCount + "号数";
            }
            if (enables.stream().distinct().allMatch(x -> x.equals("2"))) {
                examApplyDto.setEnabled("2");
            }
            examApplyDto.setRemainCount(remainCountStr);
            examApplyDto.setScheduleApm(earliestTime);
            return examApplyDto;
        } catch (Exception e) {
            log.error("getScheduleDate:" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 总计 -预约时段信息 已使用数量信息
     *
     * @param date
     * @param apmCodes
     * @param examClass
     * @return
     */
    @Override
    public ExamScheduleApm examScheduleApm(String date, List<String> apmCodes, String examClass) {
        ExamScheduleApmDto dto = new ExamScheduleApmDto();
        dto.setScheduleDate(date);
        dto.setApmCodes(apmCodes);
        // 获取时段日期占用数量
        List<ExamScheduleApm> list = examScheduleApmMapper.getScheduleApm(dto);
        ExamScheduleApm apm = new ExamScheduleApm();
        // 已使用数量 人数 / 号源系数
        int coun = 0;
        double organs = 0.0;
        // 不释放号源数量 人数 / 号源系数
        int countRecycle = 0;
        double organsRecycle = 0.0;
        for (ExamScheduleApm apmItem : list) {
            coun += ((apmItem.getCount() == null) ? 0 : apmItem.getCount());
            organs += ((apmItem.getOrgans() == null) ? 0.0 : apmItem.getOrgans());
            // 取消预约不释放号源
            boolean isCancelNoFreeConfig = isCancelNoFreeConfig(examClass);
            if (isCancelNoFreeConfig) {
                countRecycle += ((apmItem.getCountRecycle() == null) ? 0 : apmItem.getCountRecycle());
                organsRecycle += ((apmItem.getOrgansRecycle() == null) ? 0.0 : apmItem.getOrgansRecycle());
            }
        }
        apm.setCount(coun);
        apm.setOrgans(organs);
        apm.setCountRecycle(countRecycle);
        apm.setOrgansRecycle(organsRecycle);
        return apm;
    }

    public Map<String, ExamApplyDto> getGreenChannel(Map<String, DictScheduleApmDto> apmMap, String date, boolean isExamClass4Organ, String examClass) {
        Map<String, ExamApplyDto> map = new TreeMap<>();
        for (String key : apmMap.keySet()) {
            DictScheduleApmDto esa = apmMap.get(key);
            double countLimit = (esa.getMaxLimit() != null) ? esa.getMaxLimit() : 0.0;
            ExamScheduleApm apm = examScheduleApm(date, esa.getApmCodes(), examClass);
            int count = apm.getCount();
            double organs = apm.getOrgans();
            double num = count;
            if (isExamClass4Organ) {
                num = organs;
            }
            double remainCount = BigDecimalUtil.subtract(countLimit, num);
            String enabled = "1";
            if (remainCount <= 0.0) {
                enabled = "0";
                remainCount = 0.0;
            }
            String stopFlag = "0";
            if ("1".equals(esa.getStopFlag()) && ("0".equals(enabled) || "1".equals(enabled))) {
                stopFlag = "1";
            } else if ("0".equals(esa.getStopFlag()) && "0".equals(enabled)) {
                stopFlag = "2";
            }
            ExamApplyDto exam = new ExamApplyDto();
            exam.setCount(count);
            if (!isExamClass4Organ && count > 0) {
                organs = count;
            }
            exam.setOrgans(organs);
            exam.setStopFlag(stopFlag);
            exam.setLimitCount(countLimit + "");
            exam.setApmFlag(esa.getApmFlag());
            exam.setApm(esa.getScheduleApm());
            exam.setScheduleApm(esa.getScheduleApm());
            exam.setEndTime(esa.getTimeEnd());
            exam.setStartTime(esa.getTimeStart());
            exam.setApmCode(esa.getApmCode());
            exam.setRemainCount(String.valueOf(remainCount));
            map.put(esa.getScheduleApm(), exam);
        }
        return map;
    }

    public Map<String, DictScheduleApmDto> apmScheduleRule(Map<String, DictScheduleApmDto> apmMap, ExamApplyDto examApply) {
        for (Object key : apmMap.keySet().toArray()) {
            DictScheduleApmDto dsa = apmMap.get(key);
            boolean bool = isEnabledScheduleApm(dsa, examApply, examApply.getDate());
            if (bool) {
                bool = quantityRuleJudge(examApply, dsa, examApply.getDate());
            }
            if (!bool) {
                apmMap.remove(key);
            }
        }
        return apmMap;
    }

    /**
     * 根据占号系数
     * 获取时段剩余可预约数量
     *
     * @param apmMap
     * @param date
     * @param name
     * @param examApply
     * @return
     */
    @Override
    public Map<String, ExamApplyDto> getOrgansInfo(Map<String, DictScheduleApmDto> apmMap, String date, String name, ExamApplyDto examApply) {
        double reqCount = examApply.getReqCount();
        Map<String, Object> apmCountMap = new HashMap<>();
        Map<String, Object> regularCountMap = new HashMap<>();
        List<String> newList = new ArrayList<>();
        // 所有可用的时段列表
        for (Object key : apmMap.keySet().toArray()) {
            DictScheduleApmDto dsa = apmMap.get(key);
            dsa.setReservaNum((examApply.getReservaNum() == null) ? 0.0 : examApply.getReservaNum());
            double maxLimit = (dsa.getMaxLimit() != null) ? dsa.getMaxLimit() : 0.0;
            ExamScheduleApm examScheduleApm = examScheduleApm(date, dsa.getApmCodes(), examApply.getExamClass());
            double organsRecycle = 0.0;
            if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                organsRecycle = ((examScheduleApm.getOrgansRecycle() == null || examScheduleApm.getOrgansRecycle() < 0.0) ? 0.0 : examScheduleApm.getOrgansRecycle());
            }
            double organs = BigDecimalUtil.add(examScheduleApm.getOrgans(), organsRecycle);
            double organsCount = BigDecimalUtil.subtract(maxLimit, organs);
            double currentRemainCount = configServiceImpl.currentRemainCount(date, dsa.getTimeStart(), dsa.getTimeEnd(), maxLimit, organs);
            if (currentRemainCount >= 0.0 && organsCount > currentRemainCount) {
                organsCount = currentRemainCount;
            }
            // 有可用的号数
            if (organsCount > 0.0) {
                double regularCount = dsa.getRegularMinNum() * reqCount;
                boolean flag = false;
                String newScheduleApm = dsa.getScheduleApm() + dsa.getTimeStart();
                for (String apm : newList) {
                    if (apm.equals(newScheduleApm)) {
                        double apmTotal = BigDecimalUtil.add(organsCount, Double.parseDouble(apmCountMap.get(apm).toString()));
                        if (apmTotal < 0.0) {
                            apmTotal = 0.0;
                        }
                        Double regularTotalNum = BigDecimalUtil.add(regularCount, Double.parseDouble(regularCountMap.get(apm).toString()));
                        regularCountMap.put(newScheduleApm, regularTotalNum);
                        apmCountMap.put(newScheduleApm, apmTotal);
                        flag = true;
                    }
                }
                if (!flag) {
                    newList.add(newScheduleApm);
                    apmCountMap.put(newScheduleApm, organsCount);
                    regularCountMap.put(newScheduleApm, regularCount);
                }
            }
        }
        // 时段可能不属于一个队列，遍历出队列名称你
        List<String> queueNameList = new ArrayList<>();
        for (String ampKey : apmMap.keySet()) {
            DictScheduleApmDto esa = apmMap.get(ampKey);
            if (!queueNameList.contains(esa.getQueueName())) {
                queueNameList.add(esa.getQueueName());
            }
        }
        Map<String, ExamApplyDto> map = new HashMap<>();
        Map<String, List<String>> apmCodeMap = new TreeMap<>();
        List<DictScheduleApmDto> sameQueueApms = apmMap.values().stream().filter(x -> queueNameList.contains(x.getQueueName()))
                .collect(Collectors.toList());

        for (DictScheduleApmDto apmDto : sameQueueApms) {
            //
            boolean set = false;
            // 是否启用
            boolean isEnabled = true;
            //是否跳过， 已经计算过的时段就跳过
            boolean isPass = false;

            String newScheduleApmKey = apmDto.getScheduleApm() + apmDto.getTimeStart();
            if (map.containsKey(newScheduleApmKey)) {
                ExamApplyDto dto = map.get(newScheduleApmKey);
                if (Objects.nonNull(dto) && "1".equals(dto.getEnabled())) {
                    // 已经计算过并且可用的时段，就直接跳过
                    isPass = true;
                    break;
                } else {
                    // 如果已经计算过但是，未启用的时段 就标记为不可用
                    isEnabled = false;
                }
            }
            // 已经计算过的时段就跳过
            if (isPass) {
                continue;
            }
            // 不可用的时段标记set=true
            if (!isEnabled) {
                set = true;
            }
            String enabled = "1";

            double apmLimit = (apmDto.getMaxLimit() != null) ? apmDto.getMaxLimit() : 0.0;
            // 获取已预约的数据
            ExamScheduleApm esa2 = examScheduleApm(date, apmDto.getApmCodes(), examApply.getExamClass());
            double organsRecycle2 = 0.0;

            if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                organsRecycle2 = ((esa2.getOrgansRecycle() == null) ? 0.0 : esa2.getOrgansRecycle());
            }
            // 剩余可预约数量
            double leftOrgansNum = BigDecimalUtil.subtract(BigDecimalUtil.subtract(apmLimit, esa2.getOrgans()), organsRecycle2);
            double apmRecycle = BigDecimalUtil.add(esa2.getOrgans(), organsRecycle2);
            // 不关预约数，根据当前时间动态减少号源
            double currentRemainCount = configServiceImpl.currentRemainCount(date, apmDto.getTimeStart(), apmDto.getTimeEnd(), apmLimit, apmRecycle);
            if (currentRemainCount >= 0.0 && leftOrgansNum > currentRemainCount) {
                leftOrgansNum = currentRemainCount;
            }
            if (leftOrgansNum <= 0.0) {
                continue;
            }
            double organsTotal = leftOrgansNum;
            // 当前时段的结束时间
            String time = apmDto.getTimeEnd();
            // 是否还有剩余的号
            boolean isRemainNum = true;
            // 是否可以继续预约
            boolean isContent = true;
            // 如果剩余号数小于请求号数
            if (leftOrgansNum < reqCount) {
                isContent = false;
                List<String> list = new ArrayList<>();
                List<DictScheduleApmDto> sameQueueApms2 = apmMap.values().stream().filter(x -> queueNameList.contains(x.getQueueName()))
                        .collect(Collectors.toList());
                for (DictScheduleApmDto apmItem : sameQueueApms2) {
                    if (apmItem.getTimeStart().compareTo(apmDto.getTimeStart()) <= 0) {
                        continue;
                    }
                    //下个时段的开始时间
                    String timeEnd = DateUtil.addSecond(time, 1);
                    if (!timeEnd.equals(apmItem.getTimeStart())) {
                        continue;
                    }
                    time = apmItem.getTimeEnd();
                    // 下个时段的限额
                    double nextApmLimit = (apmItem.getMaxLimit() != null) ? apmItem.getMaxLimit() : 0.0;
                    ExamScheduleApm nextUseNum = examScheduleApm(date, apmItem.getApmCodes(), examApply.getExamClass());
                    double nextOrgans = nextUseNum.getOrgans();
                    double nextOrgansRecycle = 0.0;
                    if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                        nextOrgansRecycle = ((nextUseNum.getOrgansRecycle() == null) ? 0.0 : nextUseNum.getOrgansRecycle());
                    }
                    double nextOrgansCount = BigDecimalUtil.subtract(BigDecimalUtil.subtract(nextApmLimit, nextOrgans), nextOrgansRecycle);
                    if (nextOrgansCount <= 0.0) {
                        break;
                    }
                    organsTotal = BigDecimalUtil.add(organsTotal, nextOrgansCount);
                    list.add(apmItem.getApmCode());
                    if (organsTotal >= reqCount) {
                        apmCodeMap.put(apmDto.getApmCode(), list);
                        isRemainNum = true;
                        break;
                    }
                }
                enabled = "0";
            }
            ExamApplyDto examApplyDto = new ExamApplyDto();
            examApplyDto.setEnabled(enabled);
            examApplyDto.setApm(apmDto.getScheduleApm());
            examApplyDto.setScheduleApm(apmDto.getScheduleApm());
            examApplyDto.setStartTime(apmDto.getTimeStart());
            examApplyDto.setEndTime(apmDto.getTimeEnd());
            NumberFormat nf = NumberFormat.getInstance();
            double num = Double.parseDouble(apmCountMap.get(newScheduleApmKey).toString());
            double regularNum = Double.parseDouble(regularCountMap.get(newScheduleApmKey).toString());
            if (regularNum > 0.0 && num > regularNum) {
                num = regularNum;
            }
            examApplyDto.setRemainCount(nf.format(num) + name);
            examApplyDto.setApmFlag(apmDto.getApmFlag());
            examApplyDto.setReservaNum(apmDto.getReservaNum());
            // 当前时段号源不足，加上下一个时段的号源充足的情况
            if (!isContent) {
                if (apmCodeMap.containsKey(apmDto.getApmCode())) {
                    examApplyDto.setEnabled("1");
                    isRemainNum = true;
                } else {
                    // 加上下一个时段充足的情况
                    List<String> code = apmCodeMap.values().stream()
                            .filter(x -> x.contains(apmDto.getApmCode()))
                            .findFirst().orElse(null);
                    if (CollectionUtils.isNotEmpty(code)) {
                        isRemainNum = true;
                    }
                }
            }
            // 没有剩余直接返回
            if (!isRemainNum) {
                continue;
            }
            // 删除重复的数据-本身不可用，但是加上其他时段就可以用，需要把自身删除
            if (set && isEnabled && map.containsKey(newScheduleApmKey)) {
                for (String ky2 : map.keySet()) {
                    if (ky2.equals(newScheduleApmKey)) {
                        map.remove(ky2);
                    }
                }
            }
            map.put(newScheduleApmKey, examApplyDto);
        }
        return map;
    }

    /***
     * 对时段的优先级进行分组
     * @param apmMap
     * @param queues
     * @param examClass
     * @return
     */
    public Map<Integer, Map<String, DictScheduleApmDto>> getApmMap(Map<String, DictScheduleApmDto> apmMap, List<DictExamQueueDto> queues, String examClass) {
        // 检查类别是否 【以天数为单位判断队列优先级的类别】
        boolean isDayRange = false;
        if (queues.size() > 1) {
            for (DictExamQueueDto queue : queues) {
                int priorityOrder = (queue.getPriorityOrder() == null) ? 0 : queue.getPriorityOrder();
                if (priorityOrder > 0) {
                    isDayRange = true;
                    break;
                }
            }
            if (isDayRange) {
                // 检查类别是否 【以天数为单位判断队列优先级的类别】
                isDayRange = configServiceImpl.isPriorityFirstByDay(examClass);
            }
        }
        // 队列没有优先级 或者 【以天数为单位判断队列优先级的类别】 为false，直接返回空
        if (!isDayRange) {
            return null;
        }
        Map<Integer, Map<String, DictScheduleApmDto>> allApmMap = new LinkedHashMap<>();
        Map<String, DictScheduleApmDto> dMap = new TreeMap<>();
        int priorityOrderMax = 0;
        queues.sort(Comparator.comparing(DictExamQueueDto::getPriorityOrder, Comparator.nullsFirst(Integer::compareTo).reversed()));
        for (DictExamQueueDto deq : queues) {
            boolean isPeerPriority = false;
            int priorityOrder = (deq.getPriorityOrder() == null) ? 0 : deq.getPriorityOrder();
            if (priorityOrder >= priorityOrderMax) {
                isPeerPriority = true;
            }
            priorityOrderMax = priorityOrder;
            if (!isPeerPriority) {
                dMap = new HashMap<>();
            }
            Iterator<Map.Entry<String, DictScheduleApmDto>> it = apmMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, DictScheduleApmDto> obj = it.next();
                String key = obj.getKey();
                DictScheduleApmDto dsa = obj.getValue();
                if (deq.getQueueName().equals(dsa.getQueueName())) {
                    dMap.put(key, dsa);
                    it.remove();
                }
            }
            if (MapUtils.isNotEmpty(dMap)) {
                allApmMap.put(priorityOrder, dMap);
            }
        }
        return allApmMap;
    }

    /**
     * @param examApply
     * @param date
     * @return
     * @description 获取可以预约的时段列表
     * @author ryan.li
     * @date 2022/10/18 10:00
     */
    public JsonResult getScheduleApm(ExamApplyDto examApply, String date) {
        boolean isGreenChannel = StringUtils.isNotBlank(examApply.getIsGreenChannel());
        List<DictExamQueueDto> lsQueue = getQueueList(examApply);
        examApply.setDate(date);
        if (CollectionUtils.isEmpty(lsQueue)) {
            String queueNameStr = (examApply.getQueueName() != null) ? examApply.getQueueName() : "";
            return JsonResultUtil.failure("由于系统未设置" + examApply.getExamClass() + "检查类别" + queueNameStr + "的可预约队列，您的检查申请暂时不能预约，如有疑问请到护士站咨询！");
        }
        List<DictExamQueueDto> queues;
        if (isGreenChannel) {
            queues = new ArrayList<>(lsQueue);
        } else {
            if (examApply.getBeginDays() > 0) {
                // 构建队列可以预约的天数 提前2天 必须提前X天进行预约
                // 开放预约日期 可以预约一周内 0-7 超过7天的时间就不能够进行预约
                for (DictExamQueueDto queueItem : lsQueue) {
                    int expireDays = (queueItem.getExpireDays() == null) ? 0 : queueItem.getExpireDays();
                    if (examApply.getBeginDays() < expireDays) {
                        queueItem.setExpireDays(examApply.getBeginDays());
                    }
                }
            }
            // 过滤掉不符合条件的队列
            queues = getQueueListByDate(lsQueue, date, null);
        }
        if (CollectionUtils.isEmpty(queues)) {
            return JsonResultUtil.failure("没有可预约的时段！");
        }

        // 获取占号数量
        getOrgansOrPower(examApply);

        DictScheduleApmDto dictScheduleApmDto = new DictScheduleApmDto();
        String beginTime = "";
        if (isGreenChannel) {
            dictScheduleApmDto.setIsGreenChannel(examApply.getIsGreenChannel());
        } else {
            int itemBeginTime = (examApply.getBeginTime() == null) ? 0 : examApply.getBeginTime();
            if (itemBeginTime != 0) {
                Map<String, Object> map = DateUtil.getAfterTime(itemBeginTime);
                String beginDate = map.get("date") + "";
                if (date.compareTo(beginDate) < 0) {
                    return JsonResultUtil.failure("未达到项目可预约时间,请刷新");
                }
                if (date.compareTo(beginDate) == 0) {
                    beginTime = map.get("time") + "";
                }
            }
            int clamBeforesTime = (examApply.getClamBeforesTime() == null) ? 0 : examApply.getClamBeforesTime();
            if (clamBeforesTime != 0) {
                Map<String, Object> map2 = DateUtil.getAfterTime(clamBeforesTime);
                String beginDate2 = map2.get("date") + "";
                if (date.compareTo(beginDate2) < 0) {
                    return JsonResultUtil.failure("未达到项目可预约时间,请刷新");
                }
                if (date.compareTo(beginDate2) == 0 && clamBeforesTime > itemBeginTime) {
                    beginTime = map2.get("time") + "";
                }
            }
        }
        if (date.compareTo(DateUtil.getCurrDateStr()) == 0 || StringUtils.isNotBlank(beginTime)) {
            String currTime = DateUtil.getCurrentTime();
            if (StringUtils.isNotBlank(beginTime)) {
                currTime = beginTime;
            }
            dictScheduleApmDto.setCurrTime(currTime);
        }
        dictScheduleApmDto.setQueues(queues);
        dictScheduleApmDto.setScheduleDate(date);
        dictScheduleApmDto.setWeekDate(DateUtil.getWeek(date));
        dictScheduleApmDto.setStaffName(examApply.getStaffName());
        // 获取所有的时段列表
        Map<String, DictScheduleApmDto> apmMap = getScheduleApmMap(dictScheduleApmDto);
        // 提取时段优先级
        Map<Integer, Map<String, DictScheduleApmDto>> allApmMap = getApmMap(apmMap, queues, examApply.getExamClass());

        Map<String, ExamApplyDto> resultMap = new TreeMap<>();
        List<ExamApplyDto> lsExamApplyDto = new ArrayList<>();
        if (isGreenChannel) {
            // 绿通
            resultMap = getGreenChannel(apmMap, date, examApply.getIsExamClass4Organ(), examApply.getExamClass());
        } else if (MapUtils.isNotEmpty(allApmMap)) {
            // 有队列优先级
            boolean isNext = false;
            for (Map.Entry<Integer, Map<String, DictScheduleApmDto>> integerMapEntry : allApmMap.entrySet()) {
                apmMap = integerMapEntry.getValue();
                apmMap = apmScheduleRule(apmMap, examApply);
                if (examApply.getIsExamClass4Organ()) {
                    resultMap = getOrgansInfo(apmMap, date, "号数", examApply);
                } else {
                    resultMap = getCountInfo(apmMap, date, "人", examApply);
                }
                if (MapUtils.isNotEmpty(resultMap)) {
                    Object[] array = resultMap.keySet().toArray();
                    for (Object key : array) {
                        ExamApplyDto ea = resultMap.get(key);
                        if ("1".equals(ea.getEnabled())) {
                            isNext = true;
                            break;
                        }
                    }
                }
                if (isNext) {
                    break;
                }
            }
        } else { // 非绿通且没有优先级的情况
            // 时段预约规则
            apmMap = apmScheduleRule(apmMap, examApply);
            if (examApply.getIsExamClass4Organ()) {
                resultMap = getOrgansInfo(apmMap, date, "号数", examApply);
            } else {
                resultMap = getCountInfo(apmMap, date, "人", examApply);
            }
        }
        Object[] apmMapKey = resultMap.keySet().toArray();
        for (Object apmKey : apmMapKey) {
            ExamApplyDto examApplyDto = resultMap.get(apmKey);
            lsExamApplyDto.add(examApplyDto);
        }
        listSortStartTime(lsExamApplyDto);
        return JsonResultUtil.success("成功", lsExamApplyDto);
    }

    /**
     * 按照 startTime 开始时间进行排序操作
     *
     * @param list
     */
    @Override
    public void listSortStartTime(List<ExamApplyDto> list) {
        Collections.sort(list, (o1, o2) -> {
            SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
            try {
                Date dt1 = format.parse(o1.getStartTime().trim());
                Date dt2 = format.parse(o2.getStartTime().trim());
                if (dt1.getTime() > dt2.getTime()) {
                    return 1;
                }
                if (dt1.getTime() < dt2.getTime()) {
                    return -1;
                }
                return 0;
            } catch (Exception e) {
                return 0;
            }
        });
    }

    @Override
    public Map<String, ExamApplyDto> getCountInfo(Map<String, DictScheduleApmDto> apmMap, String date, String unitName, ExamApplyDto examApply) {
        double reqCount = examApply.getReqCount();
        Map<String, ExamApplyDto> map = new TreeMap<>();
        ExamApplyDto examApplyDto = null;
        for (String key : apmMap.keySet()) {
            DictScheduleApmDto dsa = apmMap.get(key);
            Double countLimit = (dsa.getMaxLimit() != null) ? dsa.getMaxLimit() : 0.0;
            ExamScheduleApm examScheduleApm = examScheduleApm(date, dsa.getApmCodes(), examApply.getExamClass());
            int count = examScheduleApm.getCount();
            int countRecycle = 0;
            if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                countRecycle = ((examScheduleApm.getCountRecycle() == null) ? 0 : examScheduleApm.getCountRecycle());
            }
            double apmRecycle = BigDecimalUtil.add(count, countRecycle);
            double remainCount = BigDecimalUtil.subtract(countLimit, apmRecycle);
            // 根据事件动态减少号源，获取实时的剩余号源数量
            double currentRemainCount = configServiceImpl.currentRemainCount(date, dsa.getTimeStart(), dsa.getTimeEnd(), countLimit, apmRecycle);
            if (currentRemainCount >= 0.0 && remainCount > currentRemainCount) {
                remainCount = currentRemainCount;
            }
            double regularCount = dsa.getRegularMinNum() * reqCount;
            DecimalFormat df = new DecimalFormat("#");
            //if (remainCount >= reqCount) { // 可以预约的情况
            String newApm = dsa.getScheduleApm() + dsa.getTimeStart();
            if (map.containsKey(newApm)) {
                examApplyDto = map.get(newApm);
                String examRemainCount = examApplyDto.getRemainCount();
                if (examRemainCount.contains(unitName)) {
                    examRemainCount = examRemainCount.substring(0, examRemainCount.length() - unitName.length());
                }
                double countTotal = remainCount;
                if (StringUtils.isNotBlank(examApplyDto.getFlag())) {
                    countTotal = regularCount;
                }
                String total = df.format(Double.parseDouble(examRemainCount) + countTotal);
                examApplyDto.setRemainCount(total + unitName);
                double curLimit = (dsa.getMaxLimit() != null) ? dsa.getMaxLimit() : 0.0d;
                examApplyDto.setLimitCount(String.valueOf(curLimit + countLimit));
            } else {
                examApplyDto = new ExamApplyDto();
                examApplyDto.setApm(dsa.getScheduleApm());
                examApplyDto.setScheduleApm(dsa.getScheduleApm());
                examApplyDto.setStartTime(dsa.getTimeStart());
                examApplyDto.setEndTime(dsa.getTimeEnd());
                examApplyDto.setApmFlag(dsa.getApmFlag());
                examApplyDto.setEnabled("1");
                double remainCountL = remainCount;
                if (regularCount > 0d && remainCount > regularCount) {
                    remainCountL = regularCount;
                    examApplyDto.setFlag("1");
                }
                examApplyDto.setRemainCount(df.format(remainCountL) + unitName);
                examApplyDto.setLimitCount(String.valueOf(countLimit));
                map.put(newApm, examApplyDto);
            }
            //  }
        }
        return map;
    }


    public DictUsersDto getLoginUser() {
        Subject subject = SecurityUtils.getSubject();
        Object obj = subject.getSession().getAttribute("session.current.user");
        if (ObjectUtils.isNotEmpty(obj)) {
            return (DictUsersDto) obj;
        }
        return null;
    }

    @Override
    public DictUsersDto dictUsers(ExamApplyDto dto) {
        DictUsersDto dictUsers = new DictUsersDto();
        if (StringUtils.isNotBlank(dto.getUserId()) || StringUtils.isNotBlank(dto.getUserName()) || StringUtils.isNotBlank(dto.getStaffNo())) {
            dictUsers.setUserId(dto.getUserId());
            dictUsers.setStaffNo(dto.getStaffNo());
            dictUsers.setName(dto.getUserName());
            if (StringUtils.isBlank(dictUsers.getName())) {
                dictUsers.setName(dto.getUserId());
            }
            if (StringUtils.isNotBlank(dto.getDeviceId())) {
                dictUsers.setIpAddress(dto.getDeviceId());
            }
        } else {
            Subject subject = SecurityUtils.getSubject();
            Object obj = subject.getSession().getAttribute("session.current.user");
            if (ObjectUtils.isNotEmpty(obj)) {
                dictUsers = (DictUsersDto) obj;
            }
//            String token = RpcContext.getContext().getAttachment("sessionToken");
//            if (StringUtils.isNotBlank(token)) {
//                JwtToken.Payload payload = JwtTokenUtil.getPayloadInfo(token);
//                dictUsers = dictUsersService.getUserInfo(payload.getUserId());
//            } else
//            {
//                Subject subject = SecurityUtils.getSubject();
//                Object obj = subject.getSession().getAttribute("session.current.user");
//                if (obj != null) {
//                    dictUsers = (DictUsersDto) obj;
//                }
//            }
        }
        return dictUsers;
    }

    /**
     * 添加检查预约操作日志
     *
     * @param ea
     * @param dictUsers
     */
    public void addExamScheduleAct(ExamApplyDto ea, DictUsersDto dictUsers) {
        ExamScheduleAct act = new ExamScheduleAct();
        act.setApplyNo(ea.getApplyNo());
        act.setActType(ea.getActType());
        act.setScheduleDate(ea.getScheduleDate());
        act.setScheduleApm(ea.getScheduleApm());
        act.setQueueName(ea.getQueueName());
        act.setHospitalCode(ea.getHospitalCode());
        String userType = ConstantsUtil.UserType.DOCTOR.getType();
        act.setUserType(userType);
        act.setUserId(dictUsers.getUserId());
        act.setUserName(dictUsers.getName());
        act.setComputerName(dictUsers.getIpAddress());
        act.setTerminalType(ea.getTerminalType());
        String dateStr = ConstantsUtil.YMDHMS.format(new Date());
        String[] dateArr = dateStr.split(" ");
        act.setActDate(dateArr[0]);
        act.setActTime(dateArr[1]);
        act.setScheduledId(ea.getScheduledId());
        String actDescription = ea.getActDescription();
        if (StringUtils.isBlank(actDescription)) {
            StringBuilder sb = new StringBuilder();
            if (StringUtils.isNotBlank(ea.getName())) {
                sb.append(ea.getName()).append(",");
            }
            if (StringUtils.isNotBlank(ea.getSex())) {
                sb.append(ea.getSex() + ",");
            }
            if (StringUtils.isNotBlank(ea.getAge())) {
                sb.append(ea.getAge() + ",");
            }
            if (StringUtils.isNotBlank(ea.getSickId())) {
                sb.append("ID:" + ea.getSickId() + ",");
            }
            if (StringUtils.isNotBlank(ea.getScheduledId())) {
                sb.append("预约ID:" + ea.getScheduledId() + ",");
            }
            if (StringUtils.isNotBlank(ea.getExamClass())) {
                sb.append("检查类别:" + ea.getExamClass() + ",");
            }
            if (CollectionUtils.isNotEmpty(ea.getItems())) {
                for (ExamApplyItemDto item : ea.getItems()) {
                    sb.append(",申请单号:" + item.getApplyNo() + ",项目序号:" + item.getItemNo() + ",项目名称:" + item.getItemName());
                }
            }
            if ("2".equals(ea.getActType()) && StringUtils.isNotBlank(ea.getCancelMemo())) {
                sb.append(",取消备注:" + ea.getCancelMemo());
            }
            if (StringUtils.isNotBlank(ea.getDesc())) {
                sb.append(ea.getDesc());
            }
            if (StringUtils.isNotBlank(ea.getProcess())) {
                String process = " 系数:" + ea.getProcess();
                if (StringUtils.isNotBlank(ea.getNextOrganProcess())) {
                    process = process + " ,跨系:" + ea.getNextOrganProcess().substring(1);
                }
                sb.append(process);
            }
            actDescription = sb.toString();
        }
        act.setActDescription(actDescription);
        examScheduleActMapper.save(act);
    }

    /**
     * @param examApply
     * @param queueNameList
     * @param apmMap
     * @return
     * @description 锁定时段号源
     * @author ryan.li
     * @date 2022/10/17 15:13
     */
    @Override
    public ExamApplyDto setApmLogic(ExamApplyDto examApply, List<String> queueNameList, Map<String, DictScheduleApmDto> apmMap) {
        double reqCount = examApply.getReqCount();
        boolean isExamClass4Organ = examApply.getIsExamClass4Organ();
        String newScheduleDate = examApply.getNewScheduleDate();
        String newScheduleApm = examApply.getNewScheduleApm();
        Map<String, StringBuffer> organMap = new HashMap<>();
        Map<String, ExamApplyDto> map = new TreeMap<>();

        for (String queueName : queueNameList) {
            Map<String, List<String>> apmCodeMap = new TreeMap<>();
            for (String key : apmMap.keySet()) {
                DictScheduleApmDto esa = apmMap.get(key);
                if (!queueName.equals(esa.getQueueName())) {
                    continue;
                }
                if (!esa.getScheduleApm().equals(newScheduleApm)) {
                    continue;
                }
                ExamScheduleApm examScheduleApm = examScheduleApm(newScheduleDate, esa.getApmCodes(), examApply.getExamClass());
                double countLimit = (esa.getMaxLimit() != null) ? esa.getMaxLimit() : 0.0;
                int countRecycle = 0;
                double organsRecycle = 0.0;
                if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                    countRecycle = ((examScheduleApm.getCountRecycle() == null) ? 0 : examScheduleApm.getCountRecycle());
                    organsRecycle = ((examScheduleApm.getOrgansRecycle() == null) ? 0.0 : examScheduleApm.getOrgansRecycle());
                }
                if (isExamClass4Organ) {
                    double organs = BigDecimalUtil.add(examScheduleApm.getOrgans(), organsRecycle);
                    double organsCount = BigDecimalUtil.subtract(countLimit, organs);
                    double currentRemainCount = configServiceImpl.currentRemainCount(newScheduleDate, esa.getTimeStart(), esa.getTimeEnd(), countLimit, organs);
                    if (currentRemainCount >= 0.0 && organsCount > currentRemainCount) {
                        organsCount = currentRemainCount;
                    }
                    if (organsCount <= 0.0) {
                        break;
                    }
                    double organsTotal = organsCount;
                    String time = esa.getTimeEnd();
                    boolean isRemainNum = true;
                    boolean isRemainNumOK = false;
                    if (organsCount < reqCount) {
                        List<String> list = new ArrayList<>();
                        for (String str : apmMap.keySet()) {
                            DictScheduleApmDto apm = apmMap.get(str);
                            if (!queueName.equals(apm.getQueueName())) {
                                continue;
                            }
                            if (esa.getTimeStart().compareTo(apm.getTimeStart()) >= 0) {
                                continue;
                            }
                            String timeEnd = DateUtil.addSecond(time, 1);
                            if (!timeEnd.equals(apm.getTimeStart())) {
                                continue;
                            }
                            time = apm.getTimeEnd();
                            double nextApmLimit = (apm.getMaxLimit() != null) ? apm.getMaxLimit() : 0.0;
                            ExamScheduleApm nextUseNum = examScheduleApm(newScheduleDate, apm.getApmCodes(), examApply.getExamClass());
                            double nextOrgansRecycle = 0.0;
                            if (examApply.getIsCancelPower() != null && !examApply.getIsCancelPower()) {
                                nextOrgansRecycle = ((nextUseNum.getOrgansRecycle() == null) ? 0.0 : nextUseNum.getOrgansRecycle());
                            }
                            double nextOrgans = BigDecimalUtil.add(nextUseNum.getOrgans(), nextOrgansRecycle);
                            double nextOrgansCount = BigDecimalUtil.subtract(BigDecimalUtil.subtract(nextApmLimit, nextOrgans), apm.getReservaNum());
                            if (nextOrgansCount <= 0.0) {
                                break;
                            }
                            double needOrgans = 0.0;
                            if (BigDecimalUtil.add(organsTotal, nextOrgansCount) >= reqCount) {
                                needOrgans = BigDecimalUtil.subtract(reqCount, organsTotal);
                                organsTotal = BigDecimalUtil.add(organsTotal, needOrgans);
                            } else {
                                needOrgans = nextOrgansCount;
                                organsTotal = BigDecimalUtil.add(organsTotal, nextOrgansCount);
                            }
                            List<ExamScheduleApm> nextApmList = getExamScheduleApm(apm.getApmCode(), newScheduleDate);
                            double nextApmOrgans = 0.0;
                            double nextApmOrgansRecycle = 0.0;
                            int nextApmOrgansCount = 0;
                            if (nextApmList != null && nextApmList.size() > 0) {
                                nextApmOrgans = ((nextApmList.get(0).getOrgans() == null) ? 0.0 : nextApmList.get(0).getOrgans());
                                if (examApply.getIsCancelPower() != null && examApply.getIsCancelPower()) {
                                    nextApmOrgansRecycle = ((nextApmList.get(0).getOrgansRecycle() == null) ? 0.0 : nextApmList.get(0).getOrgansRecycle());
                                    nextApmOrgansCount = ((nextApmList.get(0).getCountRecycle() == null) ? 0 : nextApmList.get(0).getCountRecycle());
                                }
                            }
                            list.add(apm.getApmCode() + "-" + apm.getApmCode() + "=" + needOrgans + "-" + nextApmOrgans + "-" + nextUseNum.getCount() + "-" + apm.getMaxLimit() + "-" + nextApmOrgansRecycle + "-" + nextApmOrgansCount);
                            if (organsTotal == reqCount) {
                                apmCodeMap.put(esa.getApmCode(), list);
                                isRemainNumOK = true;
                                break;
                            }
                        }
                        isRemainNum = false;
                    }
                    if (isRemainNumOK) {
                        isRemainNum = true;
                    }
                    if (isRemainNum) {
                        String apm2 = queueName + esa.getScheduleApm();
                        ExamApplyDto examApplyDto = new ExamApplyDto();
                        examApplyDto.setExamClass(examApply.getExamClass());
                        examApplyDto.setScheduleDate(newScheduleDate);
                        examApplyDto.setScheduleApm(esa.getScheduleApm());
                        examApplyDto.setApmCode(esa.getApmCode());
                        examApplyDto.setStartTime(esa.getTimeStart());
                        examApplyDto.setEndTime(esa.getTimeEnd());
                        examApplyDto.setRemainCount(organsTotal + "");
                        examApplyDto.setQueueName(esa.getQueueName());
                        examApplyDto.setQueueOrder(esa.getQueueOrder());
                        examApplyDto.setOrgans(reqCount);
                        examApplyDto.setMaxLimit(esa.getMaxLimit());
                        examApplyDto.setReqReachTime(esa.getTimeSignin());
                        examApplyDto.setApmCodes(esa.getApmCodes());
                        examApplyDto.setStaffName(esa.getStaffName());
                        Iterator<Map.Entry<String, List<String>>> it = apmCodeMap.entrySet().iterator();
                        StringBuilder bf = new StringBuilder();
                        StringBuffer stb = new StringBuffer();
                        while (it.hasNext()) {
                            List<String> apmCodes = it.next().getValue();
                            for (String apmCode : apmCodes) {
                                String[] arr = apmCode.split("-");
                                if (!esa.getApmCode().equals(arr[0])) {
                                    bf.append("|" + arr[1]);
                                }
                                stb.append("," + apmCode);
                            }
                        }
                        organMap.put(queueName + esa.getScheduleApm(), stb);
                        examApplyDto.setNextApmRatio(StringUtils.isNotBlank(bf.toString()) ? bf.substring(1) : "");
                        examApplyDto.setRegularIdList(esa.getRegularIdList());
                        map.put(apm2, examApplyDto);
                    }
                }
                if (isExamClass4Organ) {
                    continue;
                }
                ExamApplyDto examApplyDto2 = null;
                int count = examScheduleApm.getCount() + countRecycle;
                double remainCount = countLimit - count;
                double currentRemainCount = configServiceImpl.currentRemainCount(newScheduleDate, esa.getTimeStart(), esa.getTimeEnd(), countLimit, count);
                if (currentRemainCount >= 0.0 && remainCount > currentRemainCount) {
                    remainCount = currentRemainCount;
                }
                if (remainCount < reqCount) {
                    continue;
                }
                String apm3 = queueName + esa.getScheduleApm();
                if (map.containsKey(apm3)) {
                    examApplyDto2 = map.get(apm3);
                    examApplyDto2.setRemainCount(Double.valueOf(examApplyDto2.getRemainCount()) + remainCount + "");
                } else {
                    examApplyDto2 = new ExamApplyDto();
                    examApplyDto2.setApmCode(esa.getApmCode());
                    examApplyDto2.setApm(apm3);
                    examApplyDto2.setEnabled("1");
                    examApplyDto2.setCount(count);
                    examApplyDto2.setStartTime(esa.getTimeStart());
                    examApplyDto2.setEndTime(esa.getTimeEnd());
                    examApplyDto2.setRemainCount(remainCount + "");
                    examApplyDto2.setQueueName(esa.getQueueName());
                    examApplyDto2.setScheduleApm(esa.getScheduleApm());
                    examApplyDto2.setQueueOrder(esa.getQueueOrder());
                    examApplyDto2.setMaxLimit(esa.getMaxLimit());
                    examApplyDto2.setRegularIdList(esa.getRegularIdList());
                    examApplyDto2.setExamClass(examApply.getExamClass());
                    examApplyDto2.setScheduleDate(newScheduleDate);
                    examApplyDto2.setReqReachTime(esa.getTimeSignin());
                    examApplyDto2.setApmCodes(esa.getApmCodes());
                    examApplyDto2.setStaffName(esa.getStaffName());
                    map.put(apm3, examApplyDto2);
                }
            }
        }

        int maxQueueOrder = 0;
        for (String mapItem : map.keySet()) {
            ExamApplyDto ead = map.get(mapItem);
            if (ead.getQueueOrder() != null && ead.getQueueOrder() > maxQueueOrder) {
                maxQueueOrder = ead.getQueueOrder();
            }
        }
        // 去除掉排序编号不等于 maxQueueOrder 的数据
        if (maxQueueOrder > 0) {
            Iterator<Map.Entry<String, ExamApplyDto>> it2 = map.entrySet().iterator();
            while (it2.hasNext()) {
                ExamApplyDto ead2 = it2.next().getValue();
                if (ead2.getQueueOrder() == null || ead2.getQueueOrder() != maxQueueOrder) {
                    it2.remove();
                }
            }
        }

        ExamApplyDto ea = null;
        StringBuffer buf = new StringBuffer();
        double remainMax = 0.0;
        for (String mapKey : map.keySet()) {
            ea = map.get(mapKey);
            double remainCount2 = Double.parseDouble(ea.getRemainCount());
            if (remainCount2 > remainMax) {
                remainMax = remainCount2;
                if (organMap.size() <= 0) {
                    continue;
                }
                buf = organMap.get(mapKey);
            }
        }
        if (Objects.nonNull(ea) && buf.length() > 0) {
            ea.setOrganMapStr(buf.toString());
        }
        return ea;
    }

    /**
     * 锁定预约时段
     *
     * @param examApply
     * @param user
     * @return
     */
    public JsonResult setApm(ExamApplyDto examApply, DictUsersDto user) {
        if (StringUtils.isNotBlank(examApply.getEndTime())) {
            String scheduleDateTime = examApply.getNewScheduleDate() + " " + examApply.getEndTime();
            String currentDateTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_DATETIME);
            if (scheduleDateTime.compareTo(currentDateTime) < 0) {
                return JsonResultUtil.failure("您预约" + examApply.getNewScheduleDate() + " " + examApply.getNewScheduleApm() + " 时间已过，请重新预约");
            }
        }
        if (!examApply.getApplyNo().startsWith("RE")) {
            String chargeFlag = getChargeFlag(examApply);
            boolean isChargeFirst = configServiceImpl.getChargeFirstSchedule(examApply);
            if (isChargeFirst && "0".equals(chargeFlag)) {
                return JsonResultUtil.failure("您的检查申请未缴费，不能预约。如有疑问请到护士站咨询!");
            }
            if (isChargeFirst && "2".equals(chargeFlag)) {
                return JsonResultUtil.failure("您的检查申请已作废或已退费，不能预约。如有疑问请到护士站咨询!");
            }
            if (isChargeFirst && "3".equals(chargeFlag)) {
                return JsonResultUtil.failure("您的检查申请已作废或已退费，不能预约。如有疑问请到护士站咨询!");
            }
        }
        String scheduleLimit = configServiceImpl.scheduleLimit2(examApply);
        if (StringUtils.isNotBlank(scheduleLimit)) {
            return JsonResultUtil.failure(scheduleLimit);
        }
        if (StringUtils.isNotBlank(examApply.getPlanMode()) || ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(examApply.getTerminalType()) || ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(examApply.getTerminalType()) || ConstantsUtil.TerminalType.SELF.getType().equals(examApply.getTerminalType()) || ConstantsUtil.TerminalType.MOBILE.getType().equals(examApply.getTerminalType())) {
            ExamApplyDto examApplyDto = new ExamApplyDto();
            examApplyDto.setApplyNo(examApply.getApplyNo());
            examApplyDto.setExamClass(examApply.getExamClass());
            examApplyDto.setHospitalCode(examApply.getHospitalCode());
            examApplyDto.setMergeNo(examApply.getMergeNo());
            examApplyDto.setPerformDept(examApply.getPerformDept());
            examApplyDto.setTerminalType(examApply.getTerminalType());
            examApplyDto.setScheduleDate(examApply.getNewScheduleDate());
            examApplyDto.setScheduleApm(examApply.getNewScheduleApm());
            examApplyDto.setStartTime(examApply.getStartTime());
            examApplyDto.setEndTime(examApply.getEndTime());
            JsonResult result = scheduleSignService.scheduleConflict(examApplyDto);
            if ("2".equals(result.getStatus())) {
                Map<String, Object> map = (Map<String, Object>) result.getResult();
                return JsonResultUtil.failure(map.get("desc") + "");
            }
        }
        String gestationalWeeks = "";
        List<ExamApplyItemDto> gestationalItems = new ArrayList<>();
        if (examApply.getSex().contains(ConstantsUtil.Gender.WOMAN.getValue())) {
            gestationalItems = getGestationalItems(examApply.getItems());
            if (CollectionUtils.isNotEmpty(gestationalItems)) {
                String lastMensesDate = examApply.getLastMensesDate();
                if (StringUtils.isBlank(lastMensesDate)) {
                    lastMensesDate = getLastMensesDate(examApply.getSickId());
                    examApply.setLastMensesDate(lastMensesDate);
                }
                if (StringUtils.isBlank(lastMensesDate)) {
                    return JsonResultUtil.failure("该检查申请需要填写末次月经日期");
                }
                int pregnantDays = DateUtil.getIntervalDays(lastMensesDate, examApply.getNewScheduleDate());
                int weeks = pregnantDays / 7;
                int days = pregnantDays % 7;
                gestationalWeeks = weeks + "周";
                if (days > 0) {
                    gestationalWeeks = gestationalWeeks + days + "天";
                }
            }
        }
        String newScheduleDate = examApply.getNewScheduleDate();
        String newScheduleApm = examApply.getNewScheduleApm();
        boolean bool2 = CollectionUtils.isNotEmpty(gestationalItems)&& !isGestationalDate(newScheduleDate, examApply.getLastMensesDate(), gestationalItems);
        if (bool2) {
            return JsonResultUtil.failure("该检查项目不在孕周天数范围内！");
        }
        List<DictExamQueueDto> lsQueue = getQueueList(examApply);
        if ( CollectionUtils.isEmpty(lsQueue)) {
            return JsonResultUtil.failure("由于系统未设置" + examApply.getExamClass() + "检查类别的可预约队列，您的检查申请暂时不能预约，如有疑问请到护士站咨询！");
        }
        List<DictExamQueueDto> queues = new ArrayList<>();
        // vip通道-绿色通道
        if (StringUtils.isNotBlank(examApply.getIsGreenChannel())) {
            queues.addAll(lsQueue);
        } else {
            queues = getQueueListByDate(lsQueue, newScheduleDate, null);
        }
        if (CollectionUtils.isEmpty(queues)) {
            return JsonResultUtil.failure("没有可预约的时段！");
        }
        DictScheduleApmDto dictScheduleApmDto = new DictScheduleApmDto();
        examApply.setUserId(user.getUserId());
        getOrgansOrPower(examApply);
        boolean isExamClass4Organ = examApply.getIsExamClass4Organ();
        double reqCount = examApply.getReqCount();
        if (StringUtils.isNotBlank(examApply.getStartTime())) {
            dictScheduleApmDto.setTimeStart(examApply.getStartTime());
        }
        if (isExamClass4Organ) {
            if (StringUtils.isBlank(examApply.getStartTime())) {
                dictScheduleApmDto.setScheduleApmStart(newScheduleApm);
            }
        } else {
            dictScheduleApmDto.setScheduleApm(newScheduleApm);
        }
        dictScheduleApmDto.setQueues(queues);
        dictScheduleApmDto.setScheduleDate(newScheduleDate);
        dictScheduleApmDto.setWeekDate(DateUtil.getWeek(newScheduleDate));
        dictScheduleApmDto.setStaffName(examApply.getStaffName());
        Map<String, DictScheduleApmDto> apmMap = getScheduleApmMap(dictScheduleApmDto);
        String status = examApply.getScheduleStatus();
        if (StringUtils.isBlank(examApply.getScheduleStatus()) || "0".equals(examApply.getScheduleStatus()) || "04".equals(examApply.getScheduleStatus()) || "1".equals(examApply.getScheduleStatus())) {
            status = "01";
        }
        ExamApplyDto updateApm = null;
        if (StringUtils.isNotBlank(examApply.getScheduledId())) {
            ExamApplyDto eaDto = new ExamApplyDto();
            Double organsReqCount = getOrgansReqCount(examApply);
            if (organsReqCount == null) {
                organsReqCount = reqCount;
            }
            eaDto.setApplyNo(examApply.getApplyNo());
            eaDto.setScheduledId(examApply.getScheduledId());
            eaDto.setMergeNo(examApply.getMergeNo());
            eaDto.setScheduleDate(examApply.getOldScheduleDate());
            eaDto.setReqCount(organsReqCount);
            eaDto.setApmCode(examApply.getApmCode());
            String actType = "U";
            if ("08".equals(status)) {
                actType = ConstantsUtil.ActType.CANCEL.getType();
                eaDto.setExamClass(examApply.getExamClass());
                eaDto.setTerminalType(examApply.getTerminalType());
            }
            eaDto.setType(ConstantsUtil.ActType.UPDATE.getType());
            cancelScheduleInfo(eaDto, isExamClass4Organ);
            updateApm = eaDto.getUpdateApm();
            eaDto.setActType(actType);
            eaDto.setScheduleApm(examApply.getOldScheduleApm());
            eaDto.setHospitalCode(examApply.getHospitalCode());
            eaDto.setTerminalType(examApply.getTerminalType());
            eaDto.setQueueName(examApply.getOldQueueName());
            eaDto.setExamClass(examApply.getExamClass());
            eaDto.setName(examApply.getName());
            eaDto.setSex(examApply.getSex());
            eaDto.setAge(examApply.getAge());
            eaDto.setSickId(examApply.getSickId());
            eaDto.setItems(examApply.getItems());
            eaDto.setDesc("[改约时取消预约]");
            addExamScheduleAct(eaDto, user);
        }

        Iterator<Map.Entry<String, DictScheduleApmDto>> iterator = apmMap.entrySet().iterator();
        while (iterator.hasNext()) {
            DictScheduleApmDto dsa = iterator.next().getValue();
            boolean enabledScheduleApm = isEnabledScheduleApm(dsa, examApply, newScheduleDate);
            if (enabledScheduleApm) {
                enabledScheduleApm = quantityRuleJudge(examApply, dsa, newScheduleDate);
            }
            List<String> regularIdList = examApply.getRegularIdList();
            if (!enabledScheduleApm) {
                iterator.remove();
            } else {
                dsa.setReservaNum((examApply.getReservaNum() == null) ? 0.0 : examApply.getReservaNum());
                dsa.setRegularIdList(regularIdList);
            }

//            List<String> regularIdList = dsa.getRegularIdList();
//            if (!enabledScheduleApm) {
//                iterator.remove();
//            } else {
//                examApply.setReservaNum((dsa.getReservaNum() == null) ? 0.0 : dsa.getReservaNum());
//                examApply.setRegularIdList(dsa.getRegularIdList());
//            }
        }
        Map<Integer, Map<String, DictScheduleApmDto>> allApmMap = getApmMap(apmMap, queues, examApply.getExamClass());
        ExamApplyDto ea = null;
        if (MapUtils.isNotEmpty(allApmMap)) {
            for (Map.Entry<Integer, Map<String, DictScheduleApmDto>> integerMapEntry : allApmMap.entrySet()) {
                apmMap = integerMapEntry.getValue();
                List<String> queueNameList = getQueueNameList(apmMap, queues);
                ea = setApmLogic(examApply, queueNameList, apmMap);
                if (ea != null) {
                    break;
                }
            }
        } else {
            List<String> queueNameList2 = getQueueNameList(apmMap, queues);
            ea = setApmLogic(examApply, queueNameList2, apmMap);
        }
        if (ea == null) {
            if (StringUtils.isBlank(examApply.getPlanMode())) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            return JsonResultUtil.failure("您预约此时段号数不足！");
        }
        String isEnoughNum = judgeOrgans(ea, isExamClass4Organ);
        double organs = (ea.getOrgans() == null) ? 1.0 : ea.getOrgans();
        if (StringUtils.isNotBlank(isEnoughNum) || organs <= 0.0) {
            if (StringUtils.isBlank(examApply.getPlanMode()) && StringUtils.isNotBlank(isEnoughNum)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
            String customPhone = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CUSTOM_PHONE.getKey());
            if (StringUtils.isNotBlank(customPhone)) {
                ExamSmsNotice esn = new ExamSmsNotice();
                esn.setSmsNo(dictSerialService.getSerialId("SMS_NO"));
                esn.setApplyNo(ea.getApplyNo());
                esn.setSmsType("3");
                String content = "预约队列：" + ea.getQueueName() + "，预约日期：" + examApply.getNewScheduleDate() + "，预约时段：" + examApply.getNewScheduleApm() + "，apmCpde：" + ea.getApmCode() + "号源修改：" + isEnoughNum + "发现异常，请检查";
                esn.setSmsContent(content);
                esn.setPhoneNumber(customPhone);
                esn.setCreateDate(DateUtil.getCurrDateStr());
                esn.setCreateTime(DateUtil.getCurrentTime());
                examSmsNoticeService.insert(esn);
            }
            if (StringUtils.isNotBlank(isEnoughNum)) {
                return JsonResultUtil.failure("您预约此时段号数已满,请选择其他时段！");
            }
        }
        // 保存预约条目
        String scheduledId = saveScheduleItem(examApply, ea, status, user.getName());
        if (StringUtils.isBlank(scheduledId)) {
            throw new BusinessException("保存预约信息失败");
        }
        ea.setScheduledId(scheduledId);
        // 保存预约时段-扣减预约数量
        saveScheduleApm(examApply, ea, user);

        if (updateApm != null) {
            // 取消预约时段
            cancelScheduleApm(updateApm);
        }
        DictExamQueueDto deq = new DictExamQueueDto();
        deq.setQueueName(ea.getQueueName());
        String queueAlias = dictExamQueueService.getQueueAlias(deq);
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("queueAlias", queueAlias);
        resultMap.put("queueName", ea.getQueueName());
        resultMap.put("scheduledId", scheduledId);
        resultMap.put("apmCode", ea.getApmCode());
        resultMap.put("priorityOrder", ea.getPriorityOrder());
        if (isExamClass4Organ) {
            resultMap.put("organs", ea.getOrgans() + "");
            resultMap.put("nextApmRatio", ea.getNextApmRatio());
        }
        resultMap.put("applyNo", examApply.getApplyNo());
        resultMap.put("examClass", examApply.getExamClass());
        resultMap.put("mergeNo", examApply.getMergeNo());
        resultMap.put("gestationalWeeks", gestationalWeeks);
        return JsonResultUtil.success("成功", resultMap);
    }

    public String judgeOrgans(ExamApplyDto ea, boolean isExamClass4Organ) {
        String scheduleDate = ea.getScheduleDate();
        String apmCode = ea.getApmCode();
        double organsTotal = 0.0;
        int countTotal = 0;
        Map<String, Object> mapOragns = new HashMap<String, Object>();
        Map<String, Object> mapCount = new HashMap<String, Object>();
        ExamScheduleApmDto esd = new ExamScheduleApmDto();
        esd.setScheduleDate(ea.getScheduleDate());
        esd.setApmCodes(ea.getApmCodes());
        List<ExamScheduleApm> list = examScheduleApmMapper.getScheduleApm(esd);
        if (list != null && list.size() > 0) {
            for (ExamScheduleApm apms : list) {
                double organs = (apms.getOrgans() == null) ? 0.0 : apms.getOrgans();
                int count = (apms.getCount() == null) ? 0 : apms.getCount();
                organsTotal += organs;
                countTotal += count;
                mapOragns.put(apms.getApmCode(), organs);
                mapCount.put(apms.getApmCode(), count);
            }
        }
        if (isExamClass4Organ) {
            String examClass = ea.getExamClass();
            String scheduleApm = ea.getScheduleApm();
            Map<String, ExamScheduleDto> apmMap = new HashMap<String, ExamScheduleDto>();
            ExamScheduleDto examSchedule = new ExamScheduleDto();
            examSchedule.setScheduledDate(scheduleDate);
            examSchedule.setScheduleApm(scheduleApm);
            examSchedule.setExamClass(examClass);
            examSchedule.setQueueName(ea.getQueueName());
            examSchedule.setMaxLimit(ea.getMaxLimit());
            examSchedule.setOrgans(ea.getOrgans());
            examSchedule.setApmCode(apmCode);
            examSchedule.setApmCodes(ea.getApmCodes());
            apmMap.put(apmCode, examSchedule);
            double nextApmRatio = 0.0;
            if (StringUtils.isNotBlank(ea.getNextApmRatio())) {
                String[] split;
                String[] nextApmRatioArr = split = ea.getNextApmRatio().split("\\|");
                for (String nextApmRatios : split) {
                    String[] apmRatioArr = nextApmRatios.split("=");
                    nextApmRatio += Double.parseDouble(apmRatioArr[1]);
                }
            }
            for (Map.Entry<String, ExamScheduleDto> entry : apmMap.entrySet()) {
                String key = entry.getKey();
                ExamScheduleDto es = entry.getValue();
                Map<String, Object> map = examScheduleService.getOragnsTotal(examSchedule);
                if (map != null && map.size() > 0) {
                    double curScheduledRatio = Double.parseDouble(map.get("organs") + "");
                    double curScheduledCount = Double.parseDouble(map.get("count") + "");
                    double num = es.getMaxLimit() - curScheduledRatio;
                    double dOrgans = ea.getOrgans() - nextApmRatio;
                    if (num < dOrgans) {
                        double oldOrgans = 0.0;
                        if (mapOragns != null && mapOragns.size() > 0) {
                            oldOrgans = Double.parseDouble(mapOragns.get(key) + "");
                        }
                        double sub = curScheduledRatio - organsTotal;
                        double newOragns = oldOrgans + sub;
                        ExamScheduleApm apm = new ExamScheduleApm();
                        apm.setCount((int) curScheduledCount);
                        apm.setOrgans(newOragns);
                        apm.setScheduleDate(es.getScheduledDate());
                        apm.setApmCode(es.getApmCode());
                        return oldOrgans + "-->" + newOragns;
                    }
                }
            }
            return "";
        }
        Map<String, Object> map2 = new HashMap<String, Object>();
        int sum = 0;
        for (String apmCodes : ea.getApmCodes()) {
            ExamScheduleDto examSchedule2 = new ExamScheduleDto();
            examSchedule2.setScheduledDate(ea.getScheduleDate());
            examSchedule2.setApmCode(apmCodes);
            int count2 = examScheduleService.getCount(examSchedule2);
            sum += count2;
            map2.put(apmCodes, count2);
        }
        double difNum = ea.getMaxLimit() - sum;
        if (difNum < 1.0) {
            int oldCount = 0;
            if (mapCount != null && mapCount.size() > 0) {
                oldCount = ((mapCount.get(apmCode) == null) ? 0 : Integer.parseInt(mapCount.get(apmCode) + ""));
            }
            int count2 = sum - countTotal;
            int newCount = oldCount + count2;
            ExamScheduleApm apm2 = new ExamScheduleApm();
            apm2.setCount(Integer.valueOf(newCount));
            apm2.setScheduleDate(scheduleDate);
            apm2.setApmCode(apmCode);
            return oldCount + "-->" + newCount;
        }
        return "";
    }

    @Override
    public List<String> getQueueNameList(Map<String, DictScheduleApmDto> apmMap, List<DictExamQueueDto> queues) {
        List<String> queueNameList = new ArrayList<String>();
        for (Object key : apmMap.keySet().toArray()) {
            DictScheduleApmDto esa = apmMap.get(key);
            if (!queueNameList.contains(esa.getQueueName())) {
                queueNameList.add(esa.getQueueName());
            }
            String keys = key.toString();
            String apmQueueName = keys.substring(0, keys.lastIndexOf("="));
            for (DictExamQueueDto deq : queues) {
                String queueName = deq.getQueueName();
                if (apmQueueName.equals(queueName)) {
                    esa.setQueueOrder(deq.getPriorityOrder());
                    break;
                }
            }
        }
        return queueNameList;
    }

    /***
     * 锁定时段梳理规则-进行处理处理
     * @param isCan
     * @param regular
     * @param isExamClass4Organ
     * @param isGreenChannel
     */
    public void lockApmRegular(boolean isCan, ExamScheduleApmRegular regular, boolean isExamClass4Organ, boolean isGreenChannel) {
        String lock = regular.getScheduleDate() + regular.getApmCode() + regular.getRegularId();
        synchronized (lock.intern()) {
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(3);
            TransactionStatus status = transactionManager.getTransaction(def);
            double count = regular.getCurrentCount();
            double currentCount = 0.0;

            QueryWrapper<ExamScheduleApmRegular> qw = new QueryWrapper<>();
            qw.eq("APM_CODE", regular.getApmCode());
            qw.eq("REGULAR_ID", regular.getRegularId());
            qw.eq("SCHEDULE_DATE", regular.getScheduleDate());
            List<ExamScheduleApmRegular> regularList = examScheduleApmRegularMapper.selectList(qw);
            if (!CollectionUtils.isEmpty(regularList)) {
                currentCount = ((regularList.get(0).getCurrentCount() == null) ? 0.0 : regularList.get(0).getCurrentCount());
            }

            if (!isExamClass4Organ) {
                QueryWrapper<ExamSchedule> query = new QueryWrapper<>();
                query.eq("APM_CODE", regular.getApmCode());
                query.eq("SCHEDULED_DATE", regular.getScheduleDate());
                query.like("REGULAR_ID", regular.getRegularId());
                currentCount = examScheduleMapper.selectCount(query);
            }
            if (isCan) {
                currentCount -= count;
            } else {
                currentCount += count;
                if (!isGreenChannel) {
                    QueryWrapper<DictScheduleApmRegular> dictScheduleApmRegular = new QueryWrapper<>();
                    dictScheduleApmRegular.eq("APM_CODE", regular.getApmCode());
                    dictScheduleApmRegular.eq("REGULAR_ID", regular.getRegularId());
                    List<DictScheduleApmRegular> dictScheduleApmRegularList = dictScheduleApmRegularMapper.selectList(dictScheduleApmRegular);
                    double maxLimit = dictScheduleApmRegularList.get(0).getMaxLimit();
                    if (currentCount > maxLimit) {
                        throw new BusinessException("您预约此时段数量规则数不足！");
                    }
                }
            }
            ExamScheduleApmRegular examScheduleApmRegular = new ExamScheduleApmRegular();
            if (currentCount < 0.0) {
                currentCount = 0.0;
            }
            examScheduleApmRegular.setCurrentCount(currentCount);
            if (regularList != null && regularList.size() > 0) {
                UpdateWrapper<ExamScheduleApmRegular> update = new UpdateWrapper<>();
                update.eq("APM_CODE", regular.getApmCode());
                update.eq("REGULAR_ID", regular.getRegularId());
                update.eq("SCHEDULE_DATE", regular.getScheduleDate());
                examScheduleApmRegularMapper.update(examScheduleApmRegular, update);
            } else {
                examScheduleApmRegular.setApmCode(regular.getApmCode());
                examScheduleApmRegular.setRegularId(regular.getRegularId());
                examScheduleApmRegular.setScheduleDate(regular.getScheduleDate());
                examScheduleApmRegularMapper.insert(examScheduleApmRegular);
            }
            transactionManager.commit(status);
        }
    }

    /**
     * 锁定修改号源数量
     *
     * @param isCan             是否取消操作
     * @param esa               预约时段日期信息
     * @param isCancelPower     回收号源
     * @param isExamClass4Organ 按项目预约量系数占号的检查类别-每个项目站一个号 如果是合单预约占用多个号
     */
    public void lockScheduleApm(boolean isCan, ExamScheduleApm esa, boolean isCancelPower, boolean isExamClass4Organ) {
        String lock = esa.getScheduleDate() + esa.getApmCode();
        synchronized (lock.intern()) {
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            /**
             * 【默认】支持当前事务；如果当前不存在事务，则创建一个新事务。（默认的事务传播行为）
             *
             *  int PROPAGATION_REQUIRED = 0;
             *  【支持事务】支持当前事物，如果当前没有事物，就以非事物方式执行。
             *  @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
             *  @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
             *
             *  int PROPAGATION_SUPPORTS = 1;]
             *  【强制使用事务】使用当前的事物，如果当前不存在事物，就抛出异常。
             *  int PROPAGATION_MANDATORY = 2;
             *  【隔离多个事务】创建一个新事物，如果当前存在事物，把当前事物挂起。
             *  @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
             *
             *  int PROPAGATION_REQUIRES_NEW = 3;
             *
             *
             *  【强制非事务】不支持当前事务，始终以非事务方式执行。
             *  @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
             *
             *  int PROPAGATION_NOT_SUPPORTED = 4;
             *
             *  【不支持事务】不支持当前事务；如果当前事务存在，则抛出异常。
             *  int PROPAGATION_NEVER = 5;
             *
             *
             *  【嵌套事务】如果当前存在事物，则在嵌套事物内执行，支持按指定范围回滚事务（通过 savepoint 机制来实现）；如果当前没有事物，新建一个事务。
             *  注意：嵌套事务的实际创建只适用于特定的事务管理器，比如 DataSourceTransactionManager 在使用 JDBC 3.0 driver 时。
             *  @see org.springframework.jdbc.datasource.DataSourceTransactionManager
             *
             *  int PROPAGATION_NESTED = 6;
             */
            def.setPropagationBehavior(3);
            TransactionStatus status = transactionManager.getTransaction(def);

            ExamScheduleApm examScheduleApm = new ExamScheduleApm();
            examScheduleApm.setApmCode(esa.getApmCode());
            examScheduleApm.setScheduleDate(esa.getScheduleDate());
            // 已经有时段占用记录
            ExamScheduleApm apm = examScheduleApmService.getExamScheduleApm(examScheduleApm);
            DictScheduleApm dsa = dictScheduleApmService.selectOneByApmCode(esa.getApmCode());
            double maxLimit = 0.0;
            if (dsa != null) {
                maxLimit = dsa.getMaxLimit();
            }
            int count = (esa.getCount() == null) ? 0 : esa.getCount();
            double organs = (esa.getOrgans() == null) ? 0.0 : esa.getOrgans();
            // 已经有时段占用记录 - 修改占用数量
            if (apm != null) {
                // 已预约数量
                int currentCount = (apm.getCount() == null) ? 0 : apm.getCount();
                double currentOrgans = (apm.getOrgans() == null) ? 0.0 : apm.getOrgans();
                int currentCountRecycle = (apm.getCountRecycle() == null) ? 0 : apm.getCountRecycle();
                double currentOrgansRecycle = (apm.getOrgansRecycle() == null) ? 0.0 : apm.getOrgansRecycle();
                // 取消预约-释放号源
                if (isCan) {
                    if (isCancelPower) {
                        // 按项目预约量系数占号
                        if (isExamClass4Organ) {
                            double organsRecycle = BigDecimalUtil.add(currentOrgansRecycle, organs);
                            if (organsRecycle > maxLimit) {
                                organsRecycle = maxLimit;
                            }
                            examScheduleApm.setOrgansRecycle(organsRecycle);
                        } else {
                            double countRecycle = BigDecimalUtil.add(currentCountRecycle, count);
                            if (countRecycle > maxLimit) {
                                countRecycle = maxLimit;
                            }
                            examScheduleApm.setCountRecycle((int) countRecycle);
                        }
                    }
                    count = currentCount - count;
                    organs = currentOrgans - organs;
                } else { // 占用号源
                    if (isCancelPower) {
                        if (isExamClass4Organ) {
                            double organsTotal = BigDecimalUtil.add(organs, currentOrgansRecycle);
                            if (organsTotal > maxLimit) {
                                double organsRecycle = BigDecimalUtil.subtract(maxLimit, organs);
                                if (organsRecycle < 0.0d) {
                                    organsRecycle = 0.0d;
                                }
                                examScheduleApm.setOrgansRecycle(organsRecycle);
                            }
                        } else {
                            double countTotal = BigDecimalUtil.add(count, currentCountRecycle);
                            if (countTotal > maxLimit) {
                                double countRecycle2 = BigDecimalUtil.subtract(maxLimit, count);
                                examScheduleApm.setCountRecycle((int) countRecycle2);
                            }
                        }
                    }
                    count += currentCount;
                    organs += currentOrgans;
                }
            }
            if (count < 0) {
                count = 0;
            }
            if (organs < 0.0) {
                organs = 0.0;
            }
            examScheduleApm.setCount(count);
            examScheduleApm.setOrgans(organs);
            // 如果不为空，且占用号源大约最大预约数量-抛出异常-锁号失败
            if (!isCan && (isExamClass4Organ && organs > maxLimit)) {
                throw new BusinessException("您预约此时段号源不足！");
            }
            if (apm != null) {
                // 创建或者修改号源剩余数量
                UpdateWrapper<ExamScheduleApm> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("SCHEDULE_DATE", esa.getScheduleDate());
                updateWrapper.eq("APM_CODE", esa.getApmCode());
                examScheduleApmMapper.update(examScheduleApm, updateWrapper);
            } else {
                examScheduleApmMapper.insert(examScheduleApm);
            }
            transactionManager.commit(status);
        }
    }

    /**
     * 记录生成预约排序号
     *
     * @param examApply
     */
    public void lockScheduleNo(ExamApplyDto examApply) {
        String lock = examApply.getExamClass() + examApply.getQueueName() + examApply.getQueueName() + examApply.getScheduleDate() + examApply.getScheduleApm();
        synchronized (lock.intern()) {
            QueryWrapper<DictExamScheduleNo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("exam_class", examApply.getExamClass());
            queryWrapper.eq("queue_name", examApply.getQueueName());
            queryWrapper.eq("schedule_date", examApply.getScheduleDate());
            queryWrapper.eq("apm", examApply.getScheduleApm());
            List<DictExamScheduleNo> scheduleNoList = dictExamScheduleNoMapper.selectList(queryWrapper);
            Integer queueNo = 1;
            DictExamScheduleNo scheduleNo = null;
            if (CollectionUtils.isNotEmpty(scheduleNoList)) {
                /**
                 * 更新最大预约值
                 */
                scheduleNo = scheduleNoList.get(0);
                queueNo = scheduleNo.getQueueNo() + 1;
                UpdateWrapper<ExamScheduleItem> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("SCHEDULED_ID", examApply.getScheduledId());
                updateWrapper.set("SCHEDULE_NO", queueNo);
                examScheduleItemMapper.update(null, updateWrapper);

                scheduleNo.setQueueNo(queueNo);
                dictExamScheduleNoMapper.updateById(scheduleNo);
            } else {
                /**
                 * 创建新的记录
                 */
                UpdateWrapper<ExamScheduleItem> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("SCHEDULED_ID", examApply.getScheduledId());
                updateWrapper.set("SCHEDULE_NO", queueNo);
                examScheduleItemMapper.update(null, updateWrapper);

                scheduleNo = new DictExamScheduleNo();
                scheduleNo.setExamClass(examApply.getExamClass());
                scheduleNo.setQueueName(examApply.getQueueName());
                scheduleNo.setScheduleDate(examApply.getScheduleDate());
                scheduleNo.setApm(examApply.getScheduleApm());
                scheduleNo.setQueueNo(queueNo);
                long id = IdWorker.getId();
                scheduleNo.setId(id);

                dictExamScheduleNoMapper.insert(scheduleNo);
            }
        }
    }

    /**
     * 扣减时段数量和预约规则数量限制
     *
     * @param examApply
     * @param ea
     * @param user
     * @return
     */
    @Override
    public int saveScheduleApm(ExamApplyDto examApply, ExamApplyDto ea, com.rt.schedulebase.dto.DictUsersDto user) {
        boolean isCancelPower = examApply.getIsCancelPower() != null && examApply.getIsCancelPower();
        ExamScheduleApm esa = new ExamScheduleApm();
        esa.setScheduleDate(examApply.getNewScheduleDate());
        esa.setApmCode(ea.getApmCode());
        if (examApply.getIsExamClass4Organ()) {
            double nextOrganTotal = 0.0;
            if (StringUtils.isNotBlank(ea.getNextApmRatio())) {
                String[] str = ea.getOrganMapStr().substring(1).split(",");
                for (String s : str) {
                    String[] arr = s.split("-");
                    String[] scheduleApm = arr[1].split("=");
                    String nextApmCode = arr[0];
                    double nextApmOrgans = Double.parseDouble(scheduleApm[1]);
                    nextOrganTotal = BigDecimalUtil.add(nextOrganTotal, nextApmOrgans);
                    ExamScheduleApm examScheduleApm = new ExamScheduleApm();
                    examScheduleApm.setScheduleDate(examApply.getNewScheduleDate());
                    examScheduleApm.setApmCode(nextApmCode);
                    examScheduleApm.setOrgans(nextApmOrgans);
                    // 锁定时段号
                    lockScheduleApm(false, examScheduleApm, isCancelPower, examApply.getIsExamClass4Organ());
                }
            }
            double currentOrgans = BigDecimalUtil.subtract(examApply.getReqCount(), nextOrganTotal);
            esa.setOrgans(currentOrgans);
        }
        // 扣减预约数量规则
        addExamScheduleApmRegular(examApply.getIsExamClass4Organ(), ea.getRegularIdList(), examApply.getNewScheduleDate(), false);
        esa.setCount(1);
        // 扣减时段数量
        lockScheduleApm(false, esa, isCancelPower, examApply.getIsExamClass4Organ());

        if (StringUtils.isBlank(examApply.getActType())) {
            examApply.setActType(ConstantsUtil.ActType.LOCK.getType());
        }
        examApply.setQueueName(ea.getQueueName());
        examApply.setScheduleDate(examApply.getNewScheduleDate());
        examApply.setScheduleApm(examApply.getNewScheduleApm());
        examApply.setRegularIdList(ea.getRegularIdList());
        examApply.setScheduledId(ea.getScheduledId());
        // 添加操作记录
        addExamScheduleAct(examApply, user);

        examApply.setExamClass(ea.getExamClass());
        // 生成预约时段排序号
        lockScheduleNo(examApply);
        return 1;
    }

    /**
     * 保存申请单预约信息
     *
     * @param examApply
     * @param ea
     * @param status
     * @param name
     * @return
     */
    @Override
    public String saveScheduleItem(ExamApplyDto examApply, ExamApplyDto ea, String status, String name) {
        int i = 0,j = 0;
        if (StringUtils.isNotBlank(examApply.getItemCode())) {
            status = "08";
            examApply.setActType(ConstantsUtil.ActType.CONFIRM.getType());
            saveRefer(examApply, ea.getQueueName());
        }
        String scheduledId = PKGeneratorSingle.getInstance().nextPKStr();
        int count = examScheduleItemServiceImpl.getExamScheduleItemSelectCount(scheduledId);
        if (count > 0) {
            return "";
        }
        List<String> strList = new ArrayList<>();
        for (ExamApplyItemDto item : examApply.getItems()) {
            ExamScheduleItem examScheduleItem = new ExamScheduleItem();
            String no = item.getApplyNo() + item.getItemNo();
            if (strList.contains(no)) {
                continue;
            }
            examScheduleItem.setApplyNo(item.getApplyNo());
            examScheduleItem.setItemNo(item.getItemNo());
            examScheduleItem.setItemName(item.getItemName());
            examScheduleItem.setScheduledId(scheduledId);
            j = examScheduleItemMapper.insert(examScheduleItem);
            strList.add(no);
        }
        ExamSchedule es = new ExamSchedule();
        es.setApplyNo(examApply.getApplyNo());
        es.setScheduleStatus(status);
        es.setScheduledId(scheduledId);
        es.setApmCode(ea.getApmCode());
        es.setQueueName(ea.getQueueName());
        es.setScheduledDate(examApply.getNewScheduleDate());
        es.setScheduleApm(examApply.getNewScheduleApm());
        es.setScheduledTime(getScheduleTime(es, ea.getStartTime()));
        es.setHospitalCode(examApply.getHospitalCode());
        es.setScheduler(name);
        es.setSchePath(ConstantsUtil.TerminalTypeSchePath.getKey(examApply.getTerminalType()));
        es.setReqReachTime(ea.getReqReachTime());
        es.setEarliestDate(examApply.getEarliestDate());
        es.setEarliestTime(examApply.getEarliestTime());
        String sb = getRegularId(ea.getRegularIdList(), examApply.getIsExamClass4Organ());
        if (StringUtils.isNotBlank(sb)) {
            es.setRegularId(sb);
        }
        String queueClass = (ea.getPriorityOrder() != null) ? ea.getPriorityOrder() : "普通";
        es.setQueueClass(queueClass);
        if (examApply.getIsExamClass4Organ()) {
            es.setOrgans(ea.getOrgans());
            es.setNextApmRatio(ea.getNextApmRatio());
        }
        // 医生排班
        String staffName = examApply.getStaffName();
        if (StringUtils.isBlank(staffName)) {
            DictScheduleApmDutyDto dsad = new DictScheduleApmDutyDto();
            dsad.setScheduleDate(examApply.getNewScheduleDate());
            dsad.setApmCodes(ea.getApmCodes());
            List<DictScheduleApmDuty> dutyList = dictScheduleApmDutyServiceImpl.getDutyList(dsad);
            if (CollectionUtils.isNotEmpty(dutyList)) {
                staffName = dutyList.get(0).getStaffName();
            }
        }
        es.setStaffName(staffName);
        // 队列号码
        String queueNoClass = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.QUEUE_NO_CLASS.getKey());
        if (StringUtils.isNotBlank(queueNoClass) && ConstantsUtil.ScheduleStatus.EIGHT.getStatus().equals(es.getScheduleStatus()) && queueNoClass.contains(examApply.getExamClass())) {
            Map<String, String> param = new HashMap<String, String>();
            param.put("queueDate", examApply.getNewScheduleDate());
            param.put("queueName", ea.getQueueName());
            param.put("queueApm", ea.getScheduleApm());
            param.put("queueClass", queueClass);
            String queueNo = examScheduleMapper.getScheduleQueueNo(param);
            es.setQueueNo(queueNo);
            ea.setQueueNo(queueNo);
        }
        i = examScheduleMapper.insert(es);
        if (i == 0 || j == 0) {
            scheduledId = "";
        }
        return scheduledId;
    }

    @Override
    public String getRegularId(List<String> regularIdList, boolean isExamClass4Organ) {
        StringBuffer sb = new StringBuffer();
        if (regularIdList != null && regularIdList.size() > 0) {
            for (String regularIds : regularIdList) {
                if (StringUtils.isBlank(regularIds)) {
                    continue;
                }
                String[] arr = regularIds.split("=");
                String regularId = "";
                for (int i = 0; i < arr.length; ++i) {
                    if (i == 0 || i == 1 || i == 3 || i == 4) {
                        regularId = regularId + "=" + arr[i];
                    }
                }
                sb.append("-" + regularId.substring(1));
            }
            if (StringUtils.isNotBlank(sb)) {
                return sb.substring(1);
            }
        }
        return "";
    }

    /**
     * 添加时段数量规则使用记录
     *
     * @param isExamClass4Organ
     * @param regularIdList
     * @param scheduleDate
     * @param isGreenChannel
     */
    public void addExamScheduleApmRegular(boolean isExamClass4Organ, List<String> regularIdList, String scheduleDate, boolean isGreenChannel) {
        if (CollectionUtils.isNotEmpty(regularIdList)) {
            for (String str : regularIdList) {
                if (StringUtils.isBlank(str)) {
                    continue;
                }
                String[] arr = str.split("=");
                ExamScheduleApmRegular regular = new ExamScheduleApmRegular();
                regular.setApmCode(arr[0]);
                regular.setRegularId(arr[1]);
                regular.setCurrentCount(Double.parseDouble(arr[3]));
                regular.setScheduleDate(scheduleDate);
                lockApmRegular(false, regular, isExamClass4Organ, isGreenChannel);
            }
        }
    }

    public String subtracDictScheduleApmRegular(boolean isExamClass4Organ, List<String> regularIdList, List<String> mergeNos, String scheduleDate, boolean isDeleteAll) {
        StringBuffer sb = new StringBuffer();
        if (regularIdList != null && regularIdList.size() > 0) {
            if (StringUtils.isBlank(regularIdList.get(0))) {
                return "";
            }
            String[] split = regularIdList.get(0).split("-");
            for (String str : split) {
                String[] arr = str.split("=");
                String apmCode = arr[0];
                String regularId = arr[1];
                double count = Double.parseDouble(arr[2]);
                double delCount = Double.parseDouble(arr[2]);
                boolean isSubtract = true;
                if (!isDeleteAll) {
                    List<String> itemCodes = new ArrayList<String>();
                    isSubtract = false;
                    if (arr.length > 3) {
                        for (String mergeNo : mergeNos) {
                            int idx = mergeNo.lastIndexOf("-");
                            String applyno = mergeNo.substring(0, idx);
                            String itemNo = mergeNo.substring(idx + 1, mergeNo.length());
                            QueryWrapper<ExamApplyItem> qw = new QueryWrapper<>();
                            qw.select("ITEM_CODE");
                            qw.eq("APPLY_NO", applyno);
                            qw.eq("ITEM_NO", itemNo);
                            List<ExamApplyItem> list = examApplyItemMapper.selectList(qw);
                            String itemCode = list.get(0).getItemCode().replace("-", "~");
                            String[] split2;
                            String[] itemCodeStr = split2 = arr[3].split(",");
                            for (String ic : split2) {
                                if (ic.equals(itemCode)) {
                                    --delCount;
                                } else {
                                    itemCodes.add(ic);
                                }
                            }
                        }
                        isSubtract = true;
                    }
                    if (delCount > 0.0) {
                        String regularIds = "-" + apmCode + "=" + regularId + "=" + delCount;
                        if (CollectionUtils.isNotEmpty(itemCodes)) {
                            regularIds = regularIds + "=" + String.join(",", itemCodes);
                        }
                        sb.append(regularIds);
                    }
                    count -= delCount;
                }
                if (isSubtract) {
                    ExamScheduleApmRegular regular = new ExamScheduleApmRegular();
                    regular.setApmCode(apmCode);
                    regular.setRegularId(regularId);
                    regular.setCurrentCount(count);
                    regular.setScheduleDate(scheduleDate);
                    lockApmRegular(true, regular, isExamClass4Organ, false);
                }
            }
        }
        return StringUtils.isNotBlank(sb) ? sb.substring(1) : "";
    }

    public List<ExamScheduleApm> getExamScheduleApm(String apmCode, String scheduleDate) {
        QueryWrapper<ExamScheduleApm> query = new QueryWrapper<>();
        query.eq("APM_CODE", apmCode);
        query.eq("SCHEDULE_DATE", scheduleDate);
        return examScheduleApmMapper.selectList(query);
    }

    /**
     * 数量规则预约量查询
     * @param apmCodes
     * @param regularId
     * @param scheduleDate
     * @param itemCodes
     * @return
     */
    public double getExamScheduleApmRegular(List<String> apmCodes, String regularId, String scheduleDate, List<String> itemCodes) {
        QueryWrapper<ExamScheduleApmRegular> query = new QueryWrapper<>();
        query.in("APM_CODE", apmCodes);
        query.eq("SCHEDULE_DATE", scheduleDate);
        query.eq("REGULAR_ID", regularId);
        List<ExamScheduleApmRegular> list = examScheduleApmRegularMapper.selectList(query);
        double currentCount = 0.0;
        for (ExamScheduleApmRegular esar : list) {
            RuleDto rule = (RuleDto) EhCacheUtil.get(ConstantsUtil.EhCacheName.regularCache.name(), regularId);
            if (rule == null) {
                rule = dictScheduleApmRegularServiceImpl.getRuleDto(regularId);
                if (rule != null) {
                    EhCacheUtil.put(ConstantsUtil.EhCacheName.regularCache.name(), regularId, (Serializable) rule);
                }
            }
            List<String> ruleitems = (rule.getExamItem() != null) ? rule.getExamItem().getValue() : null;
            boolean isItemCode = true;
            if (ruleitems != null) {
                isItemCode = false;
                for (String itemCode : itemCodes) {
                    if (ruleitems.contains(itemCode)) {
                        isItemCode = true;
                        break;
                    }
                }
            }
            if (!isItemCode) {
                continue;
            }
            currentCount += ((esar.getCurrentCount() == null) ? 0.0 : esar.getCurrentCount());
        }
        return currentCount;
    }

    public JsonResult editApm(ExamApplyDto dto, com.rt.schedulebase.dto.DictUsersDto obj) {
        dto.setScheduleStatus("08");
        return setApm(dto, obj);
    }

    /**
     * @param dto
     * @return
     * @description 根据mergeno 拆分applyNo
     * @author ryan.li
     * @date 2022/10/19 9:23
     */
    @Override
    public ExamApplyDto getApplyNos(ExamApplyDto dto) {
        ExamApplyDto eaDto = new ExamApplyDto();
        List<String> applyNos = new ArrayList<>();
        if (StringUtils.isNotBlank(dto.getMergeNo())) {
            List<String> mergeNoList = CommonUtil.split2List(dto.getMergeNo());
            if (CollectionUtils.isNotEmpty(mergeNoList)) {
                for (String mergeNo : mergeNoList) {
                    int idx = mergeNo.lastIndexOf("-");
                    String applyNo = mergeNo.substring(0, idx);
                    if (applyNos.isEmpty()) {
                        eaDto.setApplyNo(applyNo);
                        eaDto.setItemNo(Long.parseLong(mergeNo.substring(idx + 1)));
                    }
                    if (!applyNos.contains(applyNo)) {
                        applyNos.add(applyNo);
                    }
                }
            }
        } else {
            eaDto.setApplyNo(dto.getApplyNo());
            applyNos.add(dto.getApplyNo());
        }
        eaDto.setApplyNos(applyNos);
        return eaDto;
    }

    /**
     * 查询申请单预约信息
     *
     * @param dto
     * @param ea
     * @return
     */
    @Override
    public ExamApplyDto getScheduleToExamApply(ExamApplyDto dto, ExamApplyDto ea) {
        ExamApplyDto eaDto = getApplyNos(dto);
        dto.setApplyNos(eaDto.getApplyNos());
        ea.setApplyNos(eaDto.getApplyNos());
        List<ExamApplyDto> list;

        if (eaDto.getApplyNo().startsWith("RE")) {
            // RE 虚单预约
            list = examApplyMapper.getReExamSchedule(eaDto);
        } else {
            // 普通预约信息
            list = examApplyMapper.getExamSchedule(eaDto);
        }
        if ((!CollectionUtils.isEmpty(list)) && Objects.nonNull(list.get(0))) {
            ExamApplyDto es = list.get(0);
            ea.setScheduledId(es.getScheduledId());
            if (StringUtils.isNotBlank(es.getExamStatus())) {
                ea.setScheduleStatus(es.getExamStatus());
            } else {
                ea.setScheduleStatus(es.getScheduleStatus());
            }
            ea.setExamStatus(es.getExamStatus());
            ea.setScheduleHospital(es.getScheduleHospital());
            ea.setScheduleHospitalName(es.getScheduleHospitalName());
            ea.setQueueName(es.getQueueName());
            ea.setQueueNo(es.getQueueNo());
            ea.setScheduleApm(es.getScheduleApm());
            ea.setScheduleDate(es.getScheduleDate());
            ea.setOrgans(es.getOrgans());
            ea.setNextApmRatio(es.getNextApmRatio());
            ea.setMemo(es.getMemo());
            ea.setApmCode(es.getApmCode());
            ea.setExamApm(es.getExamApm());
            ea.setApmFlag(es.getApmFlag());
            ea.setLocation(es.getLocation());
            ea.setSignLocation(es.getSignLocation());
            ea.setStaffName(es.getStaffName());
            if (StringUtils.isNotBlank(ea.getApmCode())) {
                DictScheduleApmDto apm = getTimeEarliest(ea.getApmCode());
                ea.setTimeEarliest(apm.getTimeEarliest());
                ea.setTimeSignin(apm.getTimeSignin());
            }
            ea.setMergeNo(dto.getMergeNo());
            ea.setRegularIdList(Arrays.asList(es.getRegularId()));
            ea.setScheduleStatus(es.getScheduleStatus());
            ea.setSchePath(CommonUtil.convertTerminalType((es.getSchePath() == null) ? "" : es.getSchePath()));
            ea.setScheduler(es.getScheduler());
            ea.setZoneName(es.getZoneName());
            ea.setSignZoneName(es.getSignZoneName());
            ea.setItemName(es.getItemName());
            ea.setItemCode(es.getItemCode());
        }
        return ea;
    }

    /**
     * 获取时段最早检查时间
     *
     * @param apmCode
     * @return
     */
    public DictScheduleApmDto getTimeEarliest(String apmCode) {
        DictScheduleApmDto scheduleApm = new DictScheduleApmDto();
        if (StringUtils.isNotBlank(apmCode)) {
            QueryWrapper<DictScheduleApm> query = new QueryWrapper<>();
            query.select("SCHEDULE_APM", "TIME_EARLIEST", "TIME_SIGNIN", "TIME_START", "TIME_END", "MAX_LIMIT", "APM_LENGTH");
            query.eq("APM_CODE", apmCode);
            List<DictScheduleApm> list = dictScheduleApmMapper.selectList(query);
            if (CollectionUtils.isNotEmpty(list) && list.get(0) != null) {
                DictScheduleApm apm = list.get(0);

                String timeEarliest = StringUtils.isBlank(apm.getTimeEarliest()) ? apm.getTimeStart().substring(0, apm.getTimeStart().length() - 3) : apm.getTimeEarliest().substring(0, apm.getTimeEarliest().length() - 3);
                String timeSignin = StringUtils.isBlank(apm.getTimeSignin()) ? "" : apm.getTimeSignin().substring(0, apm.getTimeSignin().length() - 3);
                BeanUtils.copyProperties(apm, scheduleApm);
                scheduleApm.setTimeEarliest(timeEarliest);
                scheduleApm.setTimeSignin(timeSignin);
                String newTimeEarliest = StringUtils.isBlank(apm.getTimeEarliest()) ? "" : apm.getTimeEarliest();
                String newTimeSignin = StringUtils.isBlank(apm.getTimeSignin()) ? "" : apm.getTimeSignin();
                scheduleApm.setNewTimeEarliest(newTimeEarliest);
                scheduleApm.setNewTimeSignin(newTimeSignin);
                scheduleApm.setScheduleApm(apm.getScheduleApm());
                scheduleApm.setMaxLimit(apm.getMaxLimit());
                scheduleApm.setApmLength(apm.getApmLength());
            }
        }
        return scheduleApm;
    }

    @Override
    public String getScheduleTime(ExamSchedule es, String timeStart) {
        if (StringUtils.isBlank(timeStart)) {
            DictScheduleApm dsa = dictScheduleApmService.selectOneByApmCode(es.getApmCode());
            timeStart = dsa.getTimeStart();
        }
        String scheduleTime = examScheduleMapper.getMaxScheduleTime(es);
        if (StringUtils.isNotBlank(scheduleTime)) {
            scheduleTime = DateUtil.addSecond(scheduleTime, 1);
        } else {
            scheduleTime = timeStart;
        }
        return scheduleTime;
    }

    public String getScheduleApmScope(String timeStart, String endStart) {
        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
        try {
            Date date = df.parse(endStart);
            endStart = df.format(date.getTime() + 1000L);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        String scheduleApmScope = timeStart.substring(0, 5) + "~" + endStart.substring(0, 5);
        return scheduleApmScope;
    }

    /**
     * 获取时段列表 并且加载 时段预约规则id（setRegularIdInfo(regularIdList);）
     *
     * @param dictScheduleApmDto
     * @return
     */
    @Override
    public Map<String, DictScheduleApmDto> getScheduleApmMap(DictScheduleApmDto dictScheduleApmDto) {
        Map<String, DictScheduleApmDto> apmMap = new TreeMap<>();
        // 按日期条件查询时段列表
        List<DictScheduleApmDto> dateScheduleApm = dictScheduleApmMapper.getDateScheduleApm(dictScheduleApmDto);
        for (DictScheduleApmDto dsa : dateScheduleApm) {
            String key = dsa.getQueueName() + "=" + dsa.getTimeStart() + dsa.getDateStart() + dsa.getDateEnd();
            if (!ConstantsUtil.DictAPMStopFlag.DEL.getCode().equals(dsa.getStopFlag())) {
                apmMap.put(key, dsa);
            }
        }
        // 按周数条件查询时段列表
        List<DictScheduleApmDto> weekScheduleApm = dictScheduleApmMapper.getWeekScheduleApm(dictScheduleApmDto);
        for (DictScheduleApmDto dsa : weekScheduleApm) {
            String key = dsa.getQueueName() + "=" + dsa.getTimeStart() + dsa.getDateStart() + dsa.getDateEnd();
            if (!apmMap.containsKey(key) && (!ConstantsUtil.DictAPMStopFlag.DEL.getCode().equals(dsa.getStopFlag()))) {
                apmMap.put(key, dsa);
            }
        }
        // 按通用时段查询列表
        List<DictScheduleApmDto> commonScheduleApm = dictScheduleApmMapper.getCommonScheduleApm(dictScheduleApmDto);
        for (DictScheduleApmDto dsa : commonScheduleApm) {
            String key = dsa.getQueueName() + "=" + dsa.getTimeStart() + dsa.getDateStart() + dsa.getDateEnd();
            if (!apmMap.containsKey(key) && (!ConstantsUtil.DictAPMStopFlag.DEL.getCode().equals(dsa.getStopFlag()))) {
                apmMap.put(key, dsa);
            }
        }
        // 时段列表 key =  dsa.getQueueName() + "=" + dsa.getTimeStart() + dsa.getDateStart() + dsa.getDateEnd();
        Iterator<Map.Entry<String, DictScheduleApmDto>> its = apmMap.entrySet().iterator();
        while (its.hasNext()) {
            Map.Entry<String, DictScheduleApmDto> entry = its.next();
            DictScheduleApmDto dsa4 = entry.getValue();
            dsa4.setApmCodes(Arrays.asList(dsa4.getApmCode()));

            // 非绿色通道 且 已停用 则移除时段
            if (StringUtils.isBlank(dictScheduleApmDto.getIsGreenChannel())
                    // 只要有一个状态是停用 就算停用
                    && (ConstantsUtil.DictAPMUseStatus.FALSE.getCode().equals(dsa4.getUseStatus())
                    || ConstantsUtil.DictAPMStopFlag.STOP.getCode().equals(dsa4.getStopFlag()))) {
                its.remove();
            }
        }

        List<String> apmCodeList = new ArrayList<>();
        // 预约日期不为空
        if (StringUtils.isNotBlank(dictScheduleApmDto.getScheduleDate())) {
            its = apmMap.entrySet().iterator();
            while (its.hasNext()) {
                DictScheduleApm dsa = its.next().getValue();
                if (StringUtils.isBlank(dictScheduleApmDto.getIsGreenChannel())) {
                    // 最早预约
                    if (StringUtils.isNotBlank(dsa.getTimeScheduleFirst())
                            && Objects.nonNull(dsa.getDaysScheduleFirst()) && 0 != dsa.getDaysScheduleFirst()) {
                        // 最早预约时间
                        String scheduleFirst = dictScheduleApmDto.getScheduleDate() + " " + dsa.getTimeScheduleFirst();
                        Date scheduleFirsttDate = DateUtil.parse(scheduleFirst, DateUtil.FORMAT_DATETIME_MM);
                        Date date = new Date();
                        // 当前时间和最早预约时间的分钟差值
                        int intervalMin = DateUtil.diffMin(scheduleFirsttDate, date);
                        // 提前预约分钟数
                        int firstMin = dsa.getDaysScheduleFirst() * 24 * 60;
                        // 超过最早预约的时间
                        if (intervalMin > firstMin) {
                            its.remove();
                            continue;
                        }
                    }
                    // 最晚预约
                    if (StringUtils.isNotBlank(dsa.getTimeScheduleLatest())
                            && Objects.nonNull(dsa.getDaysScheduleLatest()) && 0 != dsa.getDaysScheduleLatest()) {

                        String scheduleLatest = dictScheduleApmDto.getScheduleDate() + " " + dsa.getTimeScheduleLatest();
                        Date scheduleLatestDate = DateUtil.parse(scheduleLatest, DateUtil.FORMAT_DATETIME_MM);
                        Date date = new Date();
                        int intervalMin = DateUtil.diffMin(scheduleLatestDate, date);
                        int latestMin = dsa.getDaysScheduleLatest() * 24 * 60;
                        if (intervalMin < latestMin) {
                            its.remove();
                            continue;
                        }
                    }
                    // 和前端传入的时间比较 最早开始和最晚结束
                    if (StringUtils.isNotBlank(dictScheduleApmDto.getCurrTime())) {
                        if (StringUtils.isNotBlank(dsa.getTimeScheduleFirst()) && (Objects.isNull(dsa.getDaysScheduleFirst()) || (0 == dsa.getDaysScheduleFirst())) && (dictScheduleApmDto.getCurrTime().compareTo(dsa.getTimeScheduleFirst()) < 0)) {
                            its.remove();
                            continue;
                        }
                        if (dsa.getTimeScheduleLatest() != null && dictScheduleApmDto.getCurrTime().compareTo(dsa.getTimeScheduleLatest()) > 0) {
                            its.remove();
                            continue;
                        }
                    }
                }
                apmCodeList.add(dsa.getApmCode());
                if (dsa.getDateStart() != null && dsa.getDateEnd() != null) {
                    String paramDate = dictScheduleApmDto.getScheduleDate();
                    // 短周期
                    if (dsa.getDateStart().length() == 5) {
                        paramDate = paramDate.substring(5);
                    }
                    if (paramDate.compareTo(dsa.getDateStart()) >= 0 && paramDate.compareTo(dsa.getDateEnd()) <= 0) {
                        continue;
                    }
                    if (dsa.getDateEnd().compareTo(dsa.getDateStart()) < 0 && paramDate.compareTo(dsa.getDateStart()) <= 0 && paramDate.compareTo(dsa.getDateEnd()) <= 0) {
                        continue;
                    }
                    if (dsa.getDateEnd().compareTo(dsa.getDateStart()) < 0 && paramDate.compareTo(dsa.getDateStart()) >= 0 && paramDate.compareTo(dsa.getDateEnd()) >= 0) {
                        continue;
                    }
                    // 日期不在 时段范围内
                    its.remove();
                }
            }
        }
        // 获取预约规则
        if (CollectionUtils.isNotEmpty(apmCodeList) && MapUtils.isNotEmpty(apmMap)) {
            // 时段编码 ，规则id列表
            Map<String, List<String>> mapRegular = new HashMap<>();
            QueryWrapper<DictScheduleApmRegular> apmRegularQueryWrapper = new QueryWrapper<>();
            apmRegularQueryWrapper.in("APM_CODE", apmCodeList);
            List<DictScheduleApmRegular> apmRegulars = dictScheduleApmRegularMapper.selectList(apmRegularQueryWrapper);

            for (DictScheduleApmRegular apmRegular : apmRegulars) {
                if (mapRegular.containsKey(apmRegular.getApmCode())) {
                    List<String> regularCodeList = mapRegular.get(apmRegular.getApmCode());
                    regularCodeList.add(apmRegular.getRegularId());
                } else {
                    List<String> regularCodeList = new ArrayList<>();
                    regularCodeList.add(apmRegular.getRegularId());
                    mapRegular.put(apmRegular.getApmCode(), regularCodeList);
                }
            }

            if (MapUtils.isNotEmpty(mapRegular)) {
                for (Map.Entry<String, DictScheduleApmDto> stringDictScheduleApmDtoEntry : apmMap.entrySet()) {
                    DictScheduleApmDto scheduleApmDto = stringDictScheduleApmDtoEntry.getValue();
                    List<String> regularIdList = mapRegular.get(scheduleApmDto.getApmCode());
                    scheduleApmDto.setRegularIdInfo(regularIdList);
                    scheduleApmDto.setRegularIdList(regularIdList);
                }
            }
        }
        return apmMap;
    }

    /**
     * 获取申请单 在时段xx是否可以用
     *
     * @param dsa
     * @param examApply
     * @param date
     * @return true 可以预约该时段 false 不可以预约
     */
    @Override
    public boolean isEnabledScheduleApm(DictScheduleApmDto dsa, ExamApplyDto examApply, String date) {
        if (dsa.getRegularIdInfo() == null) {
            return false;
        }
        List<RuleDto> ruleList = new ArrayList<>();
        List<RuleDto> excludeRuleList = new ArrayList<>();
        log.info("isEnabledScheduleApm:{}", JacksonUtil.toJsonString(dsa.getRegularIdInfo()));

        for (String regularId : dsa.getRegularIdInfo()) {
            RuleDto rule = (RuleDto) EhCacheUtil.get(ConstantsUtil.EhCacheName.regularCache.name(), regularId);
            if (Objects.isNull(rule)) {
                rule = dictScheduleApmRegularServiceImpl.getRuleDto(regularId);
                if (Objects.nonNull(rule)) {
                    EhCacheUtil.put(ConstantsUtil.EhCacheName.regularCache.name(), regularId, rule);
                }
            }
            if (Objects.isNull(rule) || (Objects.nonNull(rule) && rule.getRegularId() == null)) {
                continue;
            }
            if ("3".equals(rule.getRgularType())) {
                continue;
            }
            // 排斥规则
            if ("1".equals(rule.getExcludeFlag())) {
                excludeRuleList.add(rule);
            } else {
                // 允许规则
                ruleList.add(rule);
            }
        }
        if (CollectionUtils.isEmpty(ruleList)) {
            return false;
        }
        // 验证预约规则
        for (RuleDto rule2 : excludeRuleList) {
            boolean isExcludeStop = ruleEngineServiceImpl.ruleJudge(rule2, examApply, date);
            if (isExcludeStop) {
                return false;
            }
        }
        boolean isSchedule = true;
        for (RuleDto rule3 : ruleList) {
            boolean isStop = ruleEngineServiceImpl.ruleJudge(rule3, examApply, date);
            if (!isStop) {
                return true;
            }
            isSchedule = false;
        }
        return isSchedule;
    }

    @Override
    public boolean quantityRuleJudge(ExamApplyDto examApply, DictScheduleApmDto dsa, String date) {
        return ruleEngineServiceImpl.quantityRuleJudge(examApply, dsa, date);
    }

    public SignScheduleDto signSchedule(String signParam) {
        return signSchedule(signParam, new ExamApplyDto());
    }

    /**
     * 预约签到
     *
     * @param signParam
     * @param examApplyDto
     * @return
     */
    @Override
    public SignScheduleDto signSchedule(String signParam, ExamApplyDto examApplyDto) {
        SignScheduleDto resp = null;
        Map<String, Object> configMap = configServiceImpl.isSignScheduleByThirdWS(examApplyDto);
        // 是否调用第三方的接口进行报到
        Boolean isSignScheduleByThirdWS = (boolean) configMap.get("isSignScheduleByThirdWS");
        if (isSignScheduleByThirdWS) {
            String signUrl = String.valueOf(configMap.get("signUrl"));
            // String cancelSignUrl = String.valueOf(configMap.get("cancelSignUrl"));
            String queueNoSubStr = String.valueOf(configMap.get("queueNoSub"));
            JsonResult jsonResult = signScheduleByThirdWS(examApplyDto, signUrl, signParam, ConstantsUtil.ActType.SIGN.getType());
            if (!Objects.equals("0", jsonResult.getStatus())) {
                resp = new SignScheduleDto();
                resp.setCode(jsonResult.getStatus());
                resp.setDesc(jsonResult.getMessage());
                return resp;
            }
            if (jsonResult.getResult() == null) {
                resp = new SignScheduleDto();
                resp.setCode("-1");
                resp.setDesc("接口未返回报到信息");
                return resp;
            }
            resp = JsonUtil.toBean(JsonUtil.toJson(jsonResult.getResult()), SignScheduleDto.class);
            if (resp == null) {
                resp = new SignScheduleDto();
                resp.setCode("-1");
                resp.setDesc("接口未返回报到信息或格式错误");
                return resp;
            }
            String[] code_arr = resp.getCode().split("\\|");
            String[] desc_arr = resp.getDesc().split("\\|");
            String[] applyNo_arr = resp.getApplyNo().split("\\|");
            String[] queueNo_arr = resp.getQueueNo().split("\\|");
            String[] queueName_arr = (StringUtils.isBlank(resp.getQueueName()) ? "" : resp.getQueueName()).split("\\|");
            String[] patLocalId_arr = (StringUtils.isBlank(resp.getPatLocalId()) ? "" : resp.getPatLocalId()).split("\\|");
            String[] waitCount_arr = (StringUtils.isBlank(resp.getWaitCount()) ? "" : resp.getWaitCount()).split("\\|");
            for (int i = 0; i < code_arr.length; ++i) {
                if (examApplyDto.getApplyNo().equals(applyNo_arr[i])) {
                    SignScheduleDto resp_ = new SignScheduleDto();
                    resp_.setCode(code_arr[i]);
                    resp_.setDesc(desc_arr[i]);
                    resp_.setApplyNo(applyNo_arr[i]);
                    if (StringUtils.isNotBlank(queueNoSubStr)) {
                        int idx = Integer.parseInt(queueNoSubStr);
                        resp_.setQueueNo(StringUtils.trimToEmpty(queueNo_arr[i]).substring(idx));
                    } else {
                        resp_.setQueueNo(StringUtils.trimToEmpty(queueNo_arr[i]));
                    }
                    if (StringUtils.isNotBlank(resp.getQueueName())) {
                        resp_.setQueueName(StringUtils.trimToEmpty((queueName_arr[i] != null) ? queueName_arr[i] : ""));
                    } else {
                        resp_.setQueueName("");
                    }
                    if (StringUtils.isNotBlank(resp.getPatLocalId())) {
                        resp_.setPatLocalId(StringUtils.trimToEmpty((patLocalId_arr[i] != null) ? patLocalId_arr[i] : ""));
                    } else {
                        resp_.setPatLocalId("");
                    }
                    if (StringUtils.isNotBlank(resp.getWaitCount())) {
                        resp_.setWaitCount(StringUtils.trimToEmpty((waitCount_arr[i] != null) ? waitCount_arr[i] : ""));
                    } else {
                        resp_.setWaitCount("");
                    }
                    resp_.setSignScheduleByThirdWS(true);
                    resp = resp_;
                }
            }
        } else {
            Map<String, String> map = new HashMap<String, String>();
            map.put("applyNo", signParam);
            map.put("result", "");
            map.put("desc", "");
            // 调用  报到存储过程
            examApplyMapper.register(map);
            String result = map.get("result");
            String desc = map.get("desc");
            log.info("【报到存储过程】result：" + result + ",desc：" + desc);
            resp = new SignScheduleDto();
            if ("0".equals(desc) && StringUtils.isNotBlank(result)) {
                Map<String, String> m = CommonUtil.stringToMap(result);
                String queueNo = StringUtils.trimToEmpty(m.get("queue_no"));
                String waitCount = StringUtils.trimToEmpty(m.get("wait_count"));
                String patLocalId = StringUtils.trimToEmpty(m.get("pat_local_id"));
                String examNo = StringUtils.trimToEmpty(m.get("exam_no"));
                resp.setCode("0");
                resp.setDesc(desc);
                resp.setApplyNo(signParam);
                resp.setQueueNo(queueNo);
                resp.setWaitCount(waitCount);
                resp.setPatLocalId(patLocalId);
                resp.setExamNo(examNo);
            } else {
                resp.setCode("1");
                resp.setDesc(desc);
                resp.setApplyNo(signParam);
            }
        }
        return resp;
    }

    /**
     * 调用第三方预约报到
     *
     * @param dto
     * @param signUrl
     * @param signParam
     * @param actType
     * @return
     */
    public JsonResult signScheduleByThirdWS(ExamApplyDto dto, String signUrl, String signParam, String actType) {
        List<String> applyNos = CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
        if (applyNos.isEmpty()) {
            applyNos.add(dto.getApplyNo());
        }
        if (dto.getApplyNo().startsWith("RE")) {
            dto.setIsRefer("1");
        }
        dto.setApplyNos(applyNos);
        dto.setActType(actType);
        dto.setSignParam(signParam);
        String bodyContent = JsonUtil.toJson(dto);
        log.info("----------------调用第三方预约报到(请求地址:{},请求内容:{})-------------------", signUrl, bodyContent);
        HttpUtil httpUtil = new HttpUtil();
        String timeout = configService.getConfigByName(ConstantsUtil.ConfigName.HTTP_TIMEOUT.getKey());
        String result = httpUtil.sendHttpPostBody(signUrl, bodyContent, timeout);
        log.info("----------------调用第三方预约报到(响应内容:{})-------------------", result);
        if (StringUtils.isBlank(result)) {
            return JsonResultUtil.failure("调用接口失败,接口返回空");
        }
        return JsonUtil.toBean(result, JsonResult.class);
    }

    public List<String> getReminders(String type, String examClass, String terminalType) {
        String reserve1 = "DEFAULT";
        if (ConstantsUtil.TerminalType.DEPT.getType().equals(terminalType)) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(terminalType)) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(terminalType)) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.SELF.getType().equals(terminalType)) {
            reserve1 = "SELF";
        } else if (ConstantsUtil.TerminalType.MOBILE.getType().equals(terminalType)) {
            reserve1 = "MOBILE";
        } else if (ConstantsUtil.TerminalType.SCHEDULE_CENTER.getType().equals(terminalType)) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.SCHEDULE_MANAGE.getType().equals(terminalType)) {
            reserve1 = "CLINIC";
        }
        DictCommonUseDto dto = new DictCommonUseDto();
        dto.setName(type);
        dto.setExamClass(examClass);
        dto.setReserve1(reserve1);
        List<String> reminders = new ArrayList<>();
        List<DictCommonUse> list = dictCommonUseService.getList(dto);
        if (CollectionUtils.isEmpty(list)) {
            dto.setReserve1("DEFAULT");
            list = dictCommonUseService.getList(dto);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            for (int i = 0; i < list.size(); ++i) {
                reminders.add(list.get(i).getValue());
            }
        }
        return reminders;
    }

    @Override
    public HashMap<String, Object> converPatternMap(ExamApplyDto ea, ExamApplyDto dto) {
        HashMap<String, Object> map = new HashMap<>();
        converPatternMap(ea, map, dto, null);
        return map;
    }

    public void converPatternMap(ExamApplyDto ea, HashMap<String, Object> map, ExamApplyDto dto, String smsType) {
        if (ConstantsUtil.SmsType.SCHEDULE.getType().equals(smsType) || ConstantsUtil.SmsType.SIGNIN.getType().equals(smsType) || ConstantsUtil.SmsType.CANCLE_SCHEDULE.getType().equals(smsType) || ConstantsUtil.SmsType.UPDATE.getType().equals(smsType)) {
            ExamApplyDto eaDto = new ExamApplyDto();
            if (StringUtils.isNotBlank(dto.getMergeNo())) {
                String[] mergeArr = dto.getMergeNo().split(",");
                String merge = mergeArr[0];
                eaDto.setApplyNo(merge.substring(0, merge.lastIndexOf("-")));
                eaDto.setItemNo(Long.parseLong(merge.substring(merge.lastIndexOf("-") + 1)));
            } else {
                eaDto.setApplyNo(dto.getApplyNo());
            }
            if (StringUtils.isNotBlank(eaDto.getApplyNo())) {
                List<ExamApplyDto> examApplies = examApplyMapper.findByApplyNo(eaDto);
                if (CollectionUtils.isNotEmpty(examApplies)) {
                    ea = examApplies.get(0);
                }
            }
        }
        if (ConstantsUtil.SmsType.CANCLE_SCHEDULE.getType().equals(smsType)) {
            String actDesc = examScheduleActMapper.getCancekActDesc(ea.getApplyNo());
            map.put("CANCEL_MEMO", actDesc);
        }
        if (StringUtils.isNotBlank(ea.getExamNo())) {
            map.put("NO_", CommonUtil.toDecimal(Long.parseLong("1" + ea.getExamNo())));
        }

        map.put("IMG_NO", ea.getImgNo());
        map.put("PACS_SORT_NO", ea.getPacsSortNo());
        map.put("PACS_EXAM_DEPT", ea.getPacsExamDept());
        map.put("PLAT_EXAM_TIME", ea.getPlanExamTime());

        map.put("CASE_NO", ea.getCaseNo());
        map.put("HEIGHT", ea.getHeight());
        map.put("WEIGHT", ea.getWeight());
        map.put("EXAM_NO", ea.getExamNo());
        map.put("NURSE_UNIT", ea.getNurseUnit());
        map.put("IC_CARD", ea.getIcCard());
        map.put("SICK_ID", ea.getSickId());
        map.put("INPATIENT_NO", ea.getInpatientNo());
        map.put("PAT_LOCAL_ID", ea.getPatLocalId());
        map.put("QUEUE_NO", ea.getQueueNo());
        map.put("SCHEDULE_NO", ea.getScheduleNo());
        map.put("APPLY_NO", ea.getApplyNo());
        map.put("NAME", ea.getName());
        map.put("SEX", ea.getSex());
        map.put("AGE", ea.getAge());
        map.put("BED_NO", ea.getBedNo());
        map.put("PERFORM_DEPT_NAME", ea.getPerformDeptName());
        map.put("REQ_WARD_NAME", ea.getReqWardName());
        map.put("EXAM_CLASS", ea.getExamClass());
        map.put("SCHEDULE_DATE", ea.getScheduleDate());
        map.put("EXAM_SUB_CLASS", ea.getExamSubClass());
        map.put("DRUGTIME", ea.getDrugTime());
        map.put("PATIENT_SOURCE", ea.getPatientSource());
        map.put("MEMO", ea.getReqMemo());
        map.put("TRANS_TOOL", ea.getTransTool());
        map.put("PRINT_SYSTEM_TIME", com.rt.schedulenew.utils.util.DateUtil.getDateTime());
        map.put("REQ_PHYSICIAN", ea.getReqPhysician());
        map.put("PHYS_SIGN", ea.getPhysSign());
        map.put("CLIN_SYMP", ea.getClinSymp());
        map.put("CLIN_DIAG", ea.getClinDiag());
        map.put("RELEVANT_DIAG", ea.getRelevantDiag());
        map.put("RELEVANT_LAB_TEST", ea.getRelevantLabTest());
        map.put("REQ_DATE", ea.getReqDate());
        map.put("REQ_TIME", ea.getReqTime());
        map.put("PRIORITY_ORDER", ea.getPriorityOrder());
        map.put("OUTPATIENT_NO", ea.getOutpatientNo());
        map.put("OUT_REG_NO", ea.getOutRegNo());
        map.put("MAILING_ADDRESS", ea.getMailingAddress());
        map.put("PHONE_NUMBER", ea.getPhoneNumber());
        map.put("BIRTH_DATE", ea.getBirthDate());
        map.put("QUEUE_NAME", ea.getQueueName());
        map.put("EXAM_QUEUE", ea.getExamQueueName());
        map.put("SCHEDULE_MEMO", ea.getMemo());
        map.put("APM_NAME", ea.getScheduleApm());
        map.put("CHARGE", ea.getCharges());
        map.put("QUEUE_ALIAS", ea.getQueueAlias());
        map.put("WARD_PHONE", ea.getWardPhoneNumber());
        map.put("RESERVE1", ea.getReserve1());
        map.put("SCHE_LOCATION", ea.getLocation());
        map.put("EXAM_LOCATION", ea.getExamLocation());
        map.put("CHARGE_TYPE", ea.getChargeType());
        map.put("LIST_APPLY_NO", StringUtils.join(CommonUtil.mergeNo2ApplyNos(dto.getMergeNo()), ","));
        if (StringUtils.isNotBlank(ea.getExamStatus()) && StringUtils.isNotBlank(ea.getExamLocation())) {
            map.put("LOCATION", ea.getExamLocation());
        } else {
            map.put("LOCATION", ea.getLocation());
        }
        // 申请科室
        if (StringUtils.isBlank(ea.getReqDeptName())) {
            DictDeptDto deptDto = new DictDeptDto();
            deptDto.setDeptCode(ea.getDeptCode());
            List<DictDept> dictDepts = dictDeptService.getList(deptDto);
            if (CollectionUtils.isNotEmpty(dictDepts)) {
                map.put("REQ_DEPT_NAME", StringUtils.isBlank(dictDepts.get(0).getDeptName()) ? "" : dictDepts.get(0).getDeptName());
            }
        } else {
            map.put("REQ_DEPT_NAME", ea.getReqDeptName());
        }
        ExamScheduleActDto actDto = new ExamScheduleActDto();
        actDto.setScheduleId(ea.getScheduledId());
        actDto.setTerminalType(dto.getTerminalType());
        if (StringUtils.isBlank(ea.getExamStatus())) {
            actDto.setActType(ConstantsUtil.ActType.SCHE_PRINT.getType());
            if (Objects.equals("3", ea.getScheduleStatus())) {
                actDto.setActType(ConstantsUtil.ActType.SIGN_PRINT.getType());
            }
        } else if ("10,20,40,50".contains(ea.getExamStatus())) {
            actDto.setActType(ConstantsUtil.ActType.SIGN_PRINT.getType());
        }
        int printCnt = actService.findCount(actDto) + 1;
        if (printCnt > 1) {
            map.put("PRINTCNT", printCnt + "(补打)");
        } else {
            map.put("PRINTCNT", printCnt);
        }
        map.put("ARRIVE_TIME", ea.getScheduleApm().replace("~", "-").split("-")[0]);
        if (StringUtils.isNotBlank(smsType)) {
            map.put("ACT_TIME", DateUtil.formatDate(new Date(), DateUtil.FORMAT_DATETIME));
        }
        if (StringUtils.isNotBlank(ea.getScheduleHospital())) {
            QueryWrapper<DictHospital> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("HOSPITAL_CODE", ea.getScheduleHospital());
            DictHospital hospital = dictHospitalMapper.selectOne(queryWrapper);
            map.put("PERFORM_HOSPITAL_NAME", hospital.getHospitalName());
        }
        DictScheduleApmDto apmMap = new DictScheduleApmDto();
        String startTime = "";
        String endTime = "";
        if (StringUtils.isNotBlank(ea.getApmCode())) {
            apmMap = getTimeEarliest(ea.getApmCode());
            map.put("TIME_SIGNIN", apmMap.getTimeSignin());
            map.put("TIME_EARLIEST", apmMap.getTimeEarliest());
            startTime = apmMap.getTimeStart().substring(0, apmMap.getTimeStart().length() - 3);
            endTime = DateUtil.addSecond(apmMap.getTimeEnd(), 1);
            endTime = endTime.substring(0, apmMap.getTimeEnd().length() - 3);
            map.put("SCHEDULE_APM", startTime + "~" + endTime);
            map.put("APM_NAME", apmMap.getScheduleApm());
        }
        // 申请单列表
        List<ExamApplyItemDto> applyItems = getExamApplyItem(dto.getMergeNo(), dto);
        ea.setItems(applyItems);

        if (CollectionUtils.isNotEmpty(applyItems)) {
            List<String> itemNames = new ArrayList<String>(), notices = new ArrayList<String>(), requestList = new ArrayList<String>(), orderNos = new ArrayList<String>(), itemOrders = new ArrayList<String>();

            for (int i = 0; i < applyItems.size(); ++i) {
                ExamApplyItemDto item = applyItems.get(i);
                if (!orderNos.contains(item.getOrderNo())) {
                    orderNos.add(item.getOrderNo());
                }
                int amount = (item.getAmount() != null) ? item.getAmount() : 1;
                if (amount > 1) {
                    itemNames.add("；" + item.getItemName() + " 00d7" + amount);
                } else {
                    String itemNameIndex = i + 1 + ":" + item.getItemName();
                    itemNames.add(itemNameIndex);
                    itemOrders.add(itemNameIndex + " <" + item.getOrderNo() + ">");
                }
                if (StringUtils.isNotBlank(item.getNotice())) {
                    notices.add(item.getNotice());
                }
                requestList.add((item.getExamRequire() != null) ? item.getExamRequire() : "");
            }
            map.put("ORDER_NO", String.join(";", orderNos));
            if (CollectionUtils.isNotEmpty(requestList)) {
                List<String> examRequest = new ArrayList<>(new TreeSet<>(requestList));
                map.put("EXAM_REQUIRE", StringUtils.join(examRequest, ","));
            } else {
                map.put("EXAM_REQUIRE", "");
            }
            List<String> newNotices = CommonUtil.convertNotice(notices, ea.getPatientSource(), endTime, ea.getBirthDate());
            if (CollectionUtils.isNotEmpty(newNotices)) {
                map.put("BR_NOTICE", StringUtils.join(newNotices, "</br>"));
                map.put("NOTICE", StringUtils.join(newNotices, ""));
            } else {
                map.put("BR_NOTICE", "");
                map.put("NOTICE", "");
            }
            if (CollectionUtils.isNotEmpty(itemNames)) {
                map.put("BR_ITEM_NAME", StringUtils.join(itemNames, "</br>"));
                map.put("BR_ITEM_ORDER", StringUtils.join(itemOrders, "</br>"));
                map.put("ITEM_NAME", StringUtils.join(itemNames, "；"));
            } else {
                map.put("BR_ITEM_NAME", "");
                map.put("ITEM_NAME", "");
            }
        }
        // 模板类型 预约、报到
        String type = ConstantsUtil.ReminderType.SCHEDULE.getType();
        if ("10".equals(ea.getExamStatus())) {
            type = ConstantsUtil.ReminderType.SIGN.getType();
        }
        List<String> reminders = new ArrayList<>();

        DictExamQueue queueQuery = new DictExamQueue();
        queueQuery.setQueueName(ea.getQueueName());
        List<DictExamQueue> queues = dictExamQueueService.selectExamQueue(queueQuery);
        if (!queues.isEmpty() && StringUtils.isNotBlank(queues.get(0).getNotice())) {
            reminders.add(queues.get(0).getNotice());
        }
        if (reminders.size() < 1) {
            reminders.addAll(getReminders(type, ea.getExamClass(), dto.getTerminalType()));
        }
        List<String> newRemi = CommonUtil.convertNotice(reminders, ea.getPatientSource(), endTime, ea.getBirthDate());
        if (CollectionUtils.isNotEmpty(newRemi)) {
            map.put("REMINDER", StringUtils.join(newRemi, ","));
            map.put("BR_REMINDER", StringUtils.join(newRemi, "</br>"));
        } else {
            map.put("REMINDER", "");
            map.put("BR_REMINDER", "");
        }
        double maxLimit = (apmMap.getMaxLimit() == null) ? 0.0 : apmMap.getMaxLimit();
        int apmLength = (apmMap.getApmLength() == null) ? 0 : apmMap.getApmLength();
        // 平均每个人做检查的时间-分钟
        double avg = apmLength / maxLimit, sTime = 0.0, eTime = 0.0, nextTime = 0.0;

        ExamScheduleDto scheduleDto = new ExamScheduleDto();
        scheduleDto.setApmCode(ea.getApmCode());
        scheduleDto.setScheduleApmCodes(CommonUtil.split2List(ea.getApmCode()));
        scheduleDto.setScheduleApms(CommonUtil.split2List(ea.getScheduleApm()));
        scheduleDto.setScheduledDate(ea.getScheduleDate());
        scheduleDto.setQueueNames(CommonUtil.split2List(ea.getQueueName()));
        // 占号系数
        scheduleDto.setIsExamClassRatio(configService.getOrganExamClassList().contains(dto.getExamClass()));
        scheduleDto.setScheduleStatus("1");

        // 获取预约信息-根据预约日期-计算等待时间
//        List<ExamSchedule> examScheduleList = examScheduleService.getExamScheduleByNxtApm(scheduleDto);
//        if (CollectionUtils.isNotEmpty(examScheduleList)) {
//            for (ExamSchedule examSchedule : examScheduleList) {
//                String nextApmRatio = examSchedule.getNextApmRatio()
//                        .substring(examSchedule.getNextApmRatio().lastIndexOf("\\|") + 1);
//                double nextOrgans = Double.parseDouble(nextApmRatio.substring(nextApmRatio.lastIndexOf("=") + 1));
//                DictScheduleApmDto nextApm = getTimeEarliest(examSchedule.getApmCode());
//                double nextAvg = nextApm.getApmLength() / nextApm.getMaxLimit();
//                nextTime += nextOrgans * nextAvg;
//            }
//        }
        List<ExamApplyDto> scheduleList = examScheduleMapper.getScheduleList(scheduleDto);
        if (CollectionUtils.isNotEmpty(scheduleList)) {

            for (ExamApplyDto examSchedule : scheduleList) {
                if (StringUtils.isNotBlank(examSchedule.getNextApmRatio())) {
                    String nextApmRatio = examSchedule.getNextApmRatio().substring(examSchedule.getNextApmRatio().lastIndexOf("\\|") + 1);
                    double nextOrgans = Double.parseDouble(nextApmRatio.substring(nextApmRatio.lastIndexOf("=") + 1));
                    DictScheduleApmDto nextApm = getTimeEarliest(examSchedule.getApmCode());
                    double nextAvg = nextApm.getApmLength() / nextApm.getMaxLimit();
                    nextTime += nextOrgans * nextAvg;
                }
            }

            scheduleList.sort((o1, o2) -> {
//                if (StringUtils.isNotBlank(o1.getExamQueueNo()) && StringUtils.isNotBlank(o2.getExamQueueNo())) {
//                    return (o1.getExamQueueNo().hashCode() > o2.getExamQueueNo().hashCode()) ? 0 : -1;
//                }
//                if (StringUtils.isNotBlank(o1.getQueueNo()) && StringUtils.isNotBlank(o2.getQueueNo())) {
//                    return (o1.getQueueNo().hashCode() > o2.getQueueNo().hashCode()) ? 0 : -1;
//                }
//                return 0;
                if (StringUtils.isNotBlank(o1.getExamQueueNo()) && StringUtils.isNotBlank(o2.getExamQueueNo()))
                    return (o1.getExamQueueNo().hashCode() > o2.getExamQueueNo().hashCode()) ? 0 : -1;
                if (StringUtils.isNotBlank(o1.getQueueNo()) && StringUtils.isNotBlank(o2.getQueueNo()))
                    return (o1.getQueueNo().hashCode() > o2.getQueueNo().hashCode()) ? 0 : -1;
                return 0;
            });
            for (ExamApplyDto scheduleDetailDto : scheduleList) {
                double organs = (scheduleDetailDto.getOrgans() != null) ? scheduleDetailDto.getOrgans() : 1.0;
                sTime = eTime;
                eTime += avg * organs;
                if (ea.getApplyNo().equals(scheduleDetailDto.getApplyNo())) {
                    break;
                }
            }
            String[] startTimeArr = startTime.split(":");
            int h = Integer.parseInt(startTimeArr[0]);
            int m = (int) nextTime + Integer.parseInt(startTimeArr[1]);
            sTime += m;
            eTime += m;
            int sh = (int) sTime / 60 + h;
            int sm = (int) sTime % 60;
            int eh = (int) eTime / 60 + h;
            int em = (int) eTime % 60;
            map.put("EXAM_END_APM", String.format("%02d", eh) + ":" + String.format("%02d", em));
            map.put("EXAM_START_APM", String.format("%02d", sh) + ":" + String.format("%02d", sm));
        }
        if (StringUtils.isNotBlank(ea.getLastMensesDate()) || StringUtils.isNotBlank(ea.getPregnancyDate())) {
            int pregnantDays = 0;
            if (StringUtils.isNotBlank(ea.getLastMensesDate())) {
                pregnantDays = DateUtil.getIntervalDays(ea.getLastMensesDate(), DateUtil.getCurrDateStr());
            } else {
                pregnantDays = DateUtil.getIntervalDays(ea.getPregnancyDate(), DateUtil.getCurrDateStr());
            }
            int weeks = pregnantDays / 7;
            int days = pregnantDays % 7;
            String gestationalWeeks = weeks + "周";
            if (days > 0) {
                gestationalWeeks = gestationalWeeks + days + "天";
            }
            map.put("GESTATIONAL_WEEKS", gestationalWeeks);
        } else {
            map.put("GESTATIONAL_WEEKS", "");
        }
        Set<String> flages = new HashSet<>();
        if (StringUtils.isNotBlank(ea.getFlags())) {
            List<String> flags = CommonUtil.split2List(ea.getFlags());
            for (String flag : flags) {
                flages.addAll(CommonUtil.ApplyFlag2String(flag));
            }
            map.put("EXAM_TYPE", StringUtils.join(flages, ","));
        }
    }

    /**
     * 检验合并规则
     *
     * @param itemCodes_i 检查项目1
     * @param itemCodes_j 检查项目2
     * @param ea_i        申请单1
     * @param ea_j        申请单2
     * @param isChannel
     * @return
     */
    private String mergeRule(List<String> itemCodes_i, List<String> itemCodes_j, ExamApplyDto ea_i, ExamApplyDto ea_j, boolean isChannel) {
        if (!ea_i.getSickId().equals(ea_j.getSickId())) {
            return "您选择的患者不是同一人，请确定后再次预约！";
        }
        String iExamClass = StringUtils.isBlank(ea_i.getExamClass()) ? "0" : ea_i.getExamClass();
        String jExamClass = StringUtils.isBlank(ea_j.getExamClass()) ? "0" : ea_j.getExamClass();
        if (!iExamClass.equals(jExamClass)) {
            return "您选择的申请单的检查类别不同，请确定后再次预约！";
        }
        if ((ea_i.getApplyNo().startsWith("APP") || ea_j.getApplyNo().startsWith("APP")) && !ea_i.getApplyNo().substring(0, 3).equals(ea_j.getApplyNo().substring(0, 3))) {
            return "您选择的申请单的不支持合单，请确定后再次预约！";
        }
        String iPerformDeptName = StringUtils.isBlank(ea_i.getPerformDeptName()) ? "0" : ea_i.getPerformDeptName();
        String jPerformDeptName = StringUtils.isBlank(ea_j.getPerformDeptName()) ? "0" : ea_j.getPerformDeptName();
        if (!iPerformDeptName.equals(jPerformDeptName)) {
            return "您选择的申请单的检查科室不同，请确定后再次预约！";
        }
        if (!isChannel) {
            String iPatientSource = StringUtils.isBlank(ea_i.getPatientSource()) ? "0" : ea_i.getPatientSource();
            String jPatientSource = StringUtils.isBlank(ea_j.getPatientSource()) ? "0" : ea_j.getPatientSource();
            if (!iPatientSource.equals(jPatientSource)) {
                return "您选择的申请单的患者来源不同，请确定后再次预约！";
            }
            String iChargeFlag = StringUtils.isBlank(ea_i.getChargeFlag()) ? "0" : ea_i.getChargeFlag();
            String jChargeFlag = StringUtils.isBlank(ea_j.getChargeFlag()) ? "0" : ea_j.getChargeFlag();
            if (!iChargeFlag.equals(jChargeFlag)) {
                return "您选择的申请单的患者缴费标识不同，请确定后再次预约！";
            }
            int mergeDateLimit = (ea_i.getMergeDateLimit() == null) ? -1 : ea_i.getMergeDateLimit();
            if (mergeDateLimit != -1) {
                int days = DateUtil.getIntervalDays(ea_i.getReqDate(), ea_j.getReqDate());
                if (mergeDateLimit < days) {
                    return "您选择的申请单不在合单天数控制范围内，请确定后再次预约！";
                }
            }
        }
        for (ExamApplyItemDto item_j : ea_j.getItems()) {
            if (!isChannel && itemCodes_i.contains(item_j.getItemCode())) {
                return "您选择的申请单的项目代码相同，请确定后再次预约！";
            }
            itemCodes_j.add(item_j.getItemCode());
        }
        return "";
    }

    /**
     * 去掉检查子项为空的项目
     *
     * @param items
     * @param examSubClass
     */
    public void handItemCode(List<ExamApplyItemDto> items, String examSubClass) {
        List<String> list = new ArrayList<>();
        for (ExamApplyItemDto item : items) {
            if (StringUtils.isNotBlank(item.getMobileNotice())) {
                item.setMobileNotices(JsonUtil.toList(item.getMobileNotice(), DictExamItemMobileNoticeItemDto.class));
            }
            if (StringUtils.isNotBlank(examSubClass) && StringUtils.isNotBlank(item.getExamSubClass()) && item.getExamSubClass().equals(examSubClass)) {
                list.add(item.getApplyNo() + item.getItemNo() + item.getItemCode());
            }
        }
        Iterator<ExamApplyItemDto> it = items.iterator();
        while (it.hasNext()) {
            ExamApplyItemDto e = it.next();
            String itemCode = e.getApplyNo() + e.getItemNo() + e.getItemCode();
            if (list.contains(itemCode)) {
                if (StringUtils.isNotBlank(examSubClass) && StringUtils.isNotBlank(e.getExamSubClass()) && e.getExamSubClass().equals(examSubClass)) {
                    continue;
                }
                it.remove();
            }
            list.add(itemCode);
        }
    }

    /**
     * 获取执行检查的日期
     *
     * @param applyNo
     * @return
     */
    private String getExamActForActDate(String applyNo) {
        QueryWrapper<ExamScheduleAct> query = new QueryWrapper<>();
        query.select("ACT_DATE");
        query.eq("APPLY_NO", applyNo);
        query.eq("ACT_TYPE", "6");
        query.orderByDesc("ACT_DATE");
        List<ExamScheduleAct> list = examScheduleActMapper.selectList(query);
        String actDate = "";
        if (CollectionUtils.isNotEmpty(list)) {
            actDate = list.get(0).getActDate();
        }
        return actDate;
    }

    public String getLimitType(String examClass) {
        String limitType = "1";
        boolean isExamClass4Organ = configServiceImpl.getOrganExamClassList().contains(examClass);
        if (isExamClass4Organ) {
            limitType = "2";
        }
        return limitType;
    }

    /**
     * 获取申请检查项目信息列表
     *
     * @param mergeNo
     * @param ea
     * @return
     */
    @Override
    public List<ExamApplyItemDto> getExamApplyItem(String mergeNo, ExamApplyDto ea) {
        ExamApplyItemDto examApplyItemDto = new ExamApplyItemDto();
        boolean isRe = false;
        if (StringUtils.isNotBlank(mergeNo)) {
            String[] mergeNos = mergeNo.split(",");
            List<String> applyNos = new ArrayList<String>();
            for (String str : mergeNos) {
                int idx = str.lastIndexOf("-");
                String applyno = str.substring(0, idx);
                if (applyNos.size() == 0 && applyno.startsWith("RE")) {
                    isRe = true;
                }
                applyNos.add(applyno);
            }
            examApplyItemDto.setApplyNos(applyNos);
        } else {
            if (ea.getApplyNo().startsWith("RE")) {
                isRe = true;
            }
            examApplyItemDto.setApplyNo(ea.getApplyNo());
        }
        List<ExamApplyItemDto> newItems;
        if (isRe) {
            newItems = examApplyItemMapper.getReItemList(examApplyItemDto);
        } else {
            newItems = examApplyItemMapper.getList(examApplyItemDto);
        }
        if (!CollectionUtils.isEmpty(newItems)) {
            List<String> list = CommonUtil.split2List(mergeNo);
            Iterator<ExamApplyItemDto> it = newItems.iterator();
            while (it.hasNext()) {
                ExamApplyItemDto item = it.next();
                String itemMergeNo = item.getApplyNo() + "-" + item.getItemNo();
                if ((CollectionUtils.isNotEmpty(list)) && !list.contains(itemMergeNo)) {
                    it.remove();
                }
            }
        }
        handItemCode(newItems, ea.getExamSubClass());
        return newItems;
    }

    @Override
    public boolean isScheduleSync(ExamApplyDto ea, String actType, String scheduleStatus) {
        return configService.isScheduleSync(ea, actType, scheduleStatus);
    }

    /**
     * 签到短信提醒
     *
     * @param ea
     * @param smsType
     * @param dto
     */
    @Override
    public void addExamSmsNotice(ExamApplyDto ea, String smsType, ExamApplyDto dto) {
        if (isOpenSmsNotice(ea, smsType)) {
            DictSmsContentDto dsc = new DictSmsContentDto();
            dsc.setExamClass(ea.getExamClass());
            dsc.setSmsType(smsType);
            dsc.setSmsFlag("1");
            String smsContent = "";
            String smsSourceContent = "";
            List<DictSmsContent> dictSmsContents = dictSmsContentService.getList(dsc);
            if (dictSmsContents != null && dictSmsContents.size() > 0) {
                for (DictSmsContent dictSmsContent : dictSmsContents) {
                    if (StringUtils.isBlank(dictSmsContent.getPatientSource())) {
                        smsContent = dictSmsContent.getSmsContent();
                    } else {
                        if (!dictSmsContent.getPatientSource().contains(ea.getPatientSource())) {
                            continue;
                        }
                        smsSourceContent = dictSmsContent.getSmsContent();
                    }
                }
            }
            if (StringUtils.isNotBlank(smsSourceContent)) {
                dsc.setSmsContent(smsSourceContent);
            } else if (StringUtils.isNotBlank(smsContent)) {
                dsc.setSmsContent(smsContent);
            }
            if (StringUtils.isNotBlank(dsc.getSmsContent())) {
                ExamSmsNotice esn = new ExamSmsNotice();
                esn.setSmsNo(dictSerialService.getSerialId("SMS_NO"));
                esn.setApplyNo(ea.getApplyNo());
                esn.setSmsType(smsType);
                esn.setSmsSign(dsc.getSmsSign());
                HashMap<String, Object> map = new HashMap<String, Object>();
                converPatternMap(ea, map, dto, smsType);
                esn.setSmsContent(CommonUtil.replaceMsg(dsc.getSmsContent(), map));
                esn.setPhoneNumber(ea.getPhoneNumber());
                esn.setCreateDate(DateUtil.getCurrDateStr());
                esn.setCreateTime(DateUtil.getCurrentTime());
                examSmsNoticeService.insert(esn);
            }
        }
    }

    public Boolean addSmsByItemNotice(ExamApplyDto ea, List<Map<String, String>> convertSms, ExamApplyDto dto) {
        List<String> patientSourceAll = new ArrayList<String>();
        DictSmsContentDto dsc = new DictSmsContentDto();
        dsc.setExamClass(ea.getExamClass());
        dsc.setSmsType(ConstantsUtil.SmsType.SCHEDULE.getType());
        dsc.setSmsFlag("1");
        List<DictSmsContent> lsSmsContent = dictSmsContentService.getList(dsc);
        for (DictSmsContent dictSmsContent : lsSmsContent) {
            if (StringUtils.isNotBlank(dictSmsContent.getPatientSource())) {
                List<String> patientSourceList = (List<String>) CommonUtil.split2List(dictSmsContent.getPatientSource());
                patientSourceAll.addAll(patientSourceList);
            }
        }
        if (patientSourceAll.size() > 0 && !patientSourceAll.contains(ea.getPatientSource())) {
            return false;
        }
        String SmsSign = (lsSmsContent.get(0) != null) ? lsSmsContent.get(0).getSmsSign() : null;
        for (Map<String, String> map : convertSms) {
            ExamSmsNotice esn = new ExamSmsNotice();
            esn.setSmsNo(dictSerialService.getSerialId("SMS_NO"));
            esn.setApplyNo(ea.getApplyNo());
            esn.setSmsType(ConstantsUtil.SmsType.SCHEDULE.getType());
            esn.setSmsSign(SmsSign);
            HashMap<String, Object> maps = new HashMap<String, Object>();
            converPatternMap(ea, maps, dto, ConstantsUtil.SmsType.SCHEDULE.getType());
            esn.setSmsContent(CommonUtil.replaceMsg(map.get("smsContent"), maps));
            esn.setSendDate(map.get("smsDate"));
            esn.setSendTime(map.get("smsTime"));
            esn.setPhoneNumber(ea.getPhoneNumber());
            esn.setCreateDate(DateUtil.getCurrDateStr());
            esn.setCreateTime(DateUtil.getCurrentTime());
            examSmsNoticeService.insert(esn);
        }
        return true;
    }

    private boolean isOpenSmsNotice(ExamApplyDto ea, String type) {
        boolean bool = false;
        if (ConstantsUtil.SmsType.SCHEDULE.getType().equals(type) || ConstantsUtil.SmsType.UPDATE.getType().equals(type)) {
            bool = configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_SMS_NOTICE_FOR_SCHEDULE.getKey());
        } else if (ConstantsUtil.SmsType.CANCLE_SCHEDULE.getType().equals(type)) {
            bool = configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_SMS_NOTICE_FOR_DEL_SCHEDULE.getKey());
        } else if (ConstantsUtil.SmsType.SIGNIN.getType().equals(type)) {
            bool = configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_SMS_NOTICE_FOR_SCHEDULE.getKey());
        }
        if (!bool) {
            return false;
        }
        List<DictExamQueue> dictExamQueues = configServiceImpl.getSmsNoticeQueueList();
        List<String> queueNames = new ArrayList<String>();
        for (DictExamQueue dictExamQueue : dictExamQueues) {
            queueNames.add(dictExamQueue.getQueueName());
        }
        if (queueNames.size() > 0 && !queueNames.contains(ea.getQueueName())) {
            return false;
        }
        List<String> patientSources = configServiceImpl.getSmsNoticePatientSourceList();
        return patientSources.size() <= 0 || patientSources.contains(ea.getPatientSource());
    }

    /**
     * 校验合并规则
     *
     * @param examApplyDto
     * @param dto
     * @return
     */
    public String mergeRuleForScheduleJudge(ExamApplyDto examApplyDto, ExamApplyDto dto) {
        if (StringUtils.isBlank(dto.getItemCode())) {
            String mergeNos = dto.getMergeNo();
            // 申请单号列表
            List<String> applyNos = new ArrayList<>();
            // 是否特殊通道进行预约
            boolean isChannel = !StringUtils.isBlank(dto.getIsGreenChannel()) || !StringUtils.isBlank(dto.getIsMergeChannel());

            // 合并单号列表
            List<String> mergeNoArr = new ArrayList<>();
            if (StringUtils.isNotBlank(mergeNos)) {
                String[] split = mergeNos.split(",");
                mergeNoArr = Arrays.asList(split);
                for (String mergeNo : split) {
                    int idx = mergeNo.lastIndexOf("-");
                    String applyNo = mergeNo.substring(0, idx);
                    applyNos.add(applyNo);
                }
            } else {
                applyNos = CommonUtil.split2List(dto.getApplyNo());
            }
            ExamApplyDto ea_i = new ExamApplyDto();
            List<String> itemCodes_i = new ArrayList<>();
            List<ExamApplyItemDto> items = new ArrayList<>();
            for (int i = 0; i < applyNos.size(); ++i) {
                ExamApplyDto ea_j = new ExamApplyDto();
                List<String> itemCodes_j = new ArrayList<>();
                if (applyNos.size() > 1) {
                    dto.setMergeNo(mergeNoArr.get(i));
                }
                dto.setApplyNo(applyNos.get(i));
                // 获取申请单信息
                ExamApplyDto ea = getExamApplyInfo(dto.getApplyNo(), dto.getTerminalType());
                if (Objects.isNull(ea)) {
                    return "您的检查申请单(" + (applyNos).get(i) + ")信息不存在，如有疑问请到护士站咨询！";
                }
                if (StringUtils.isNotBlank(ea.getFlags()) && StringUtils.isBlank(dto.getIsGreenChannel())) {
                    String flag = CommonUtil.subFlags(ea.getFlags(), 20);
                    if ("1".equals(flag) && (ConstantsUtil.TerminalType.SELF.getType().equals(dto.getTerminalType()) || ConstantsUtil.TerminalType.MOBILE.getType().equals(dto.getTerminalType()))) {
                        return "您的检查申请单不允许自助预约";
                    }
                    if ("2".equals(flag) && !ConstantsUtil.TerminalType.DEPT.getType().equals(dto.getTerminalType())) {
                        return "您的检查申请单只允许医技预约";
                    }
                }
                getScheduleToExamApply(dto, ea);
                ea.setIsGreenChannel(dto.getIsGreenChannel());
                if (StringUtils.isNotBlank(ea.getScheduleHospital()) && StringUtils.isNotBlank(ea.getQueueName()) && StringUtils.isNotBlank(ea.getScheduleDate()) && StringUtils.isNotBlank(ea.getScheduleApm())) {
                    boolean isQueueName = true;
                    if (StringUtils.isNotBlank(dto.getQueueName())) {
                        isQueueName = ea.getQueueName().equals(dto.getQueueName());
                    }
                    if (isQueueName && ea.getScheduleHospital().equals(dto.getHospitalCode()) && ea.getScheduleDate().equals(dto.getScheduleDate()) && ea.getScheduleApm().equals(dto.getScheduleApm())) {
                        if ("01".equals(ea.getScheduleStatus())) {
                            return ea.getScheduleStatus();
                        }
                        return "您已经预约该时段,请选择别的时段！";
                    }
                }
                if (StringUtils.isNotBlank(ea.getExamStatus()) && Integer.parseInt(ea.getExamStatus()) >= 10) {
                    log.info("检查状态:{}", ea.getExamStatus());
                    return "您选择申请单已报到或已检查!";
                }
                if (i == 0) {
                    BeanUtils.copyProperties(ea, examApplyDto);
                }
                List<ExamApplyItemDto> applyItemDtos = getExamApplyItem(dto.getMergeNo(), ea);
                if (CollectionUtils.isEmpty(applyItemDtos)) {
                    return "您的检查项目单不存在，如有疑问请到护士站咨询！";
                }
                for (ExamApplyItemDto dei : applyItemDtos) {
                    if (StringUtils.isBlank(dei.getFlags())) {
                        return "您的检查申请单项目未维护,暂不支持操作！";
                    }
                }
                if (StringUtils.isBlank(ea.getScheduledId())) {
                    ea = configServiceImpl.noShowScheduleItem(ea, applyItemDtos, dto.getTerminalType());
                    if (ea == null) {
                        continue;
                    }
                }
                ea.setItems(applyItemDtos);
                items.addAll(applyItemDtos);
                if (StringUtils.isBlank(ea_i.getApplyNo())) {
                    BeanUtils.copyProperties(ea, ea_i);
                    for (ExamApplyItemDto item_i : ea.getItems()) {
                        itemCodes_i.add(item_i.getItemCode());
                    }
                } else {
                    BeanUtils.copyProperties(ea, ea_j);
                    for (ExamApplyItemDto item_j : ea.getItems()) {
                        itemCodes_j.add(item_j.getItemCode());
                    }
                    String stat_i = StringUtils.isBlank(ea_i.getScheduleStatus()) ? "" : ea_i.getScheduleStatus();
                    String stat_j = StringUtils.isBlank(ea_j.getScheduleStatus()) ? "" : ea_j.getScheduleStatus();
                    if (StringUtils.isNotBlank(ea_i.getScheduledId()) && StringUtils.isNotBlank(ea_j.getScheduledId())) {
                        if (!ea_i.getScheduledId().equals(ea_j.getScheduledId()) && ("08".equals(stat_i) || "08".equals(stat_j))) {
                            return "您选择的申请单存在已预约单，请取消后在预约！";
                        }
                    } else if (!stat_i.equals(stat_j) && ("08".equals(stat_i) || "08".equals(stat_j))) {
                        return "您选择的申请单预约状态不一致，请确认后在预约！";
                    }
                    if (StringUtils.isBlank(ea_i.getScheduledId())) {
                        String isCompliance = mergeRule(itemCodes_i, itemCodes_j, ea_i, ea_j, isChannel);
                        if (StringUtils.isNotBlank(isCompliance)) {
                            return isCompliance;
                        }
                    }
                }
            }
            if (StringUtils.isNotBlank(dto.getSort()) && StringUtils.isNotBlank(mergeNos)) {
                String[] mergeNoArrs = mergeNos.split(",");
                int open = -1; // 已预约数量
                String scheduleId = "";
                boolean isSchedule = false;
                // 合并单号
                for (String mergeNo2 : mergeNoArrs) {
                    int idx2 = mergeNo2.lastIndexOf("-");
                    ExamScheduleItem esi = new ExamScheduleItem();
                    // 申请单
                    esi.setApplyNo(mergeNo2.substring(0, idx2));
                    // 编号
                    esi.setItemNo(Long.parseLong(mergeNo2.substring(idx2 + 1)));
                    // 已预约的申请单列表
                    List<ExamScheduleItem> list = examScheduleItemMapper.getExamScheduleItem(esi);
                    int size = list.size();

                    if (open == -1) { // 第一个合并号
                        open = size;
                        if (open > 0) {
                            scheduleId = list.get(0).getScheduledId();
                        }
                    } else if (open == size && size > 1) {
                        if (!scheduleId.equals(list.get(0).getScheduledId())) {
                            isSchedule = true;
                        }
                    } else if (open != size) {
                        isSchedule = true;
                    }
                    if (isSchedule) {
                        return "您选择的申请单的预约信息已发生改变，请刷新后在预约！";
                    }
                }
            }
            if (applyNos.size() > 1) {
                examApplyDto.setApplyNos(applyNos);
            }
            examApplyDto.setTerminalType(dto.getTerminalType());
            examApplyDto.setMergeNo(mergeNos);
            dto.setMergeNo(mergeNos);
            List<String> itemCodes = items.stream().map(x -> x.getItemCode()).collect(Collectors.toList());
            Map<String, Object> map = new HashMap<>();
            map.put("examClass", examApplyDto.getExamClass());
            map.put("itemCodes", itemCodes);
            map.put("patientSource", examApplyDto.getPatientSource());
            boolean isItemOrder = true;
            // 获取检查项目分组
            List<DictItemGroupDetailDto> digs = dictItemGroupMapper.getGroupForOrder(map);
            for (ExamApplyItemDto item : items) {
                for (DictItemGroupDetailDto dig : digs) {
                    if (item.getItemCode().equals(dig.getItemCode()) && dig.getScheduleOrder() != null) {
                        item.setScheduleOrderGroup(dig.getScheduleOrder());
                        isItemOrder = false;
                    }
                }
            }
            collectionSort(items, isItemOrder);
            examApplyDto.setItems(items);
            // 获取检查项目开始日期和时间
            Map<String, Integer> dateMap = getBeginDate(items);
            examApplyDto.setBeginTime(dateMap.get("beginTime"));
            examApplyDto.setBeginDays(dateMap.get("beginDays"));
            // 获取申请单镇静需要的时间
            int clamBeforesTime = configServiceImpl.getClamBeforesTime(examApplyDto.getExamClass(), CommonUtil.mergeNo2ApplyNos(dto.getMergeNo()));
            examApplyDto.setClamBeforesTime(clamBeforesTime);
            return "";
        }

        examApplyDto.setTerminalType(dto.getTerminalType());
        examApplyDto.setSickId(dto.getSickId());
        examApplyDto.setOutpatientNo(dto.getOutpatientNo());
        examApplyDto.setInpatientNo(dto.getInpatientNo());
        examApplyDto.setIcCard(dto.getIcCard());
        examApplyDto.setItemCode(dto.getItemCode());
        // 申请单号
        String applyNo = "RE";
        if (StringUtils.isNotBlank(dto.getSort())) {
            applyNo = dictSerialService.getSerialId("REFER_APPLY_ID", "RE");
        }
        examApplyDto.setApplyNo(applyNo);
        examApplyDto.setReqDept(dto.getDeptCode());
        examApplyDto.setDeptCode(dto.getDeptCode());
        examApplyDto.setBirthDate(dto.getBirthDate());
        examApplyDto.setIdentityCard(dto.getIdentityCard());
        examApplyDto.setName(dto.getName());
        examApplyDto.setSex(dto.getSex());
        examApplyDto.setAge(dto.getAge());
        examApplyDto.setBirthDate(dto.getBirthDate());
        examApplyDto.setPhoneNumber(dto.getPhoneNumber());
        if (StringUtils.isBlank(dto.getPriorityOrder())) {
            dto.setPriorityOrder("普通");
        }
        examApplyDto.setPriorityOrder(dto.getPriorityOrder());
        examApplyDto.setPatientSource(CommonUtil.convertPatientSource(dto.getPatientSource()));
        String lastMensesDate = null;
        if (StringUtils.isNotBlank(dto.getPregnancyDate())) {
            lastMensesDate = dto.getPregnancyDate();
        } else if (StringUtils.isNotBlank(dto.getLastMensesDate())) {
            lastMensesDate = dto.getLastMensesDate();
        } else if (StringUtils.isNotBlank(dto.getWeeks())) {
            int days = StringUtils.isNotBlank(dto.getDays()) ? Integer.parseInt(dto.getDays()) : 0;
            lastMensesDate = DateUtil.addDays(-(Integer.parseInt(dto.getWeeks()) * 7 + days) + 1);
        }
        examApplyDto.setLastMensesDate(lastMensesDate);
        examApplyDto.setReqDate(DateUtil.date2Str(new Date(), DateUtil.FORMAT_DATE));
        examApplyDto.setScheduleDate(dto.getScheduleDate());
        examApplyDto.setScheduleApm(dto.getScheduleApm());
        examApplyDto.setHospitalCode(dto.getHospitalCode());
        examApplyDto.setReqHospital(dto.getReqHospitalCode());
        examApplyDto.setMemo(dto.getMemo());

        // 获取执行的科室编码和检查项目、检查类别
        Map<String, Object> examClassAndItems = getPerformDeptCodeAndExamClassAndItems(dto.getExamClass(), dto.getHospitalCode(), dto.getItemCode());
        if (examClassAndItems != null) {
            String examClass = examClassAndItems.get("examClass").toString();
            String performDeptCode = examClassAndItems.get("performDeptCode").toString();
            String performDeptName = examClassAndItems.get("performDeptName").toString();
            examApplyDto.setExamClass(examClass);
            // 拼接新的申请单号
            StringBuilder newApplyNos = new StringBuilder();
            List<ExamApplyItemDto> examItems = (List<ExamApplyItemDto>) examClassAndItems.get("items");
            List<String> itemCodes = new ArrayList<>();
            for (ExamApplyItemDto item : examItems) {
                itemCodes.add(item.getItemCode());
                item.setApplyNo(applyNo);
                newApplyNos.append("," + applyNo + "-" + item.getItemNo());
            }
            Map<String, Object> mapGroup = new HashMap<>();
            mapGroup.put("examClass", examClass);
            mapGroup.put("itemCodes", itemCodes);
            mapGroup.put("patientSource", examApplyDto.getPatientSource());
            boolean isItemOrder = true;
            List<DictItemGroupDetailDto> digs2 = dictItemGroupMapper.getGroupForOrder(mapGroup);
            for (ExamApplyItemDto item5 : examItems) {
                for (DictItemGroupDetailDto dig2 : digs2) {
                    if (item5.getItemCode().equals(dig2.getItemCode()) && dig2.getScheduleOrder() != null) {
                        item5.setScheduleOrderGroup(dig2.getScheduleOrder());
                        isItemOrder = false;
                    }
                }
            }
            collectionSort(examItems, isItemOrder);
            examApplyDto.setItems(examItems);
            Map<String, Integer> dateMap2 = getBeginDate(examItems);
            examApplyDto.setBeginTime(dateMap2.get("beginTime"));
            examApplyDto.setBeginDays(dateMap2.get("beginDays"));
            examApplyDto.setMergeNo(newApplyNos.substring(1));
            log.info("通过检查类别和院区代码和项目获取内部检查类别和执行科室成功！参数：examClass:{},hospitalCode:{},itemCode:{}；结果：performDeptCode:{},performDeptName:{},examClass:{}", dto.getExamClass(), dto.getHospitalCode(), dto.getItemCode(), performDeptCode, performDeptName, examClass);
            return "";
        }
        log.error("通过检查类别和院区代码和项目获取内部检查类别和执行科室失败！参数：examClass:{},hospitalCode:{},itemCode:{}", dto.getExamClass(), dto.getHospitalCode(), dto.getItemCode());
        return "通过检查类别和院区代码和项目获取内部检查类别和执行科室失败！";
    }

    /**
     * 获取检查项目最早开始日期和时间
     *
     * @param items
     * @return
     */
    public Map<String, Integer> getBeginDate(List<ExamApplyItemDto> items) {
        int beginTime = 0;
        int beginDays = 0;
        for (ExamApplyItemDto itemDto : items) {
            Integer ibeginTime = itemDto.getBeginTime();
            Integer ibeginDays = itemDto.getBeginDays();
            if (ibeginTime != null) {
                beginTime = Math.max(beginTime, ibeginTime);
//                if (beginTime == 0) {
//                    beginTime = ibeginTime;
//                } else if (beginTime < ibeginTime) {
//                    beginTime = ibeginTime;
//                }
            }

            if (ibeginDays != null) {
                beginDays = Math.min(beginDays, ibeginDays);
//                if (beginDays == 0) {
//                    beginDays = ibeginDays;
//                } else {
//                    if (beginDays <= ibeginDays) {
//                        continue;
//                    }
//                    beginDays = ibeginDays;
//                }
            }
        }
        Map<String, Integer> map = new HashMap<>();
        map.put("beginTime", beginTime);
        map.put("beginDays", beginDays);
        return map;
    }

    @Override
    public void collectionSort(List<ExamApplyItemDto> items, boolean isItemOrder) {
        Collections.sort(items, (o1, o2) -> {
            long itemNoA = o1.getItemNo() + 1;
            long itemNoB = o2.getItemNo() + 2;
            long scheduleOrder = (o1.getScheduleOrder() == null) ? itemNoA : o1.getScheduleOrder();
            long scheduleOrder2 = (o2.getScheduleOrder() == null) ? itemNoB : o2.getScheduleOrder();
            if (!isItemOrder) {
                scheduleOrder = ((o1.getScheduleOrderGroup() == null) ? itemNoA : o1.getScheduleOrderGroup());
                scheduleOrder2 = ((o2.getScheduleOrderGroup() == null) ? itemNoB : o2.getScheduleOrderGroup());
            }
            if (scheduleOrder == scheduleOrder2) {
                scheduleOrder = itemNoA;
                scheduleOrder2 = itemNoB;
            }
            return (scheduleOrder > scheduleOrder2) ? -1 : 1;
        });
    }

    /**
     * 组装返回结果
     *
     * @param list
     * @param dto
     */
    public void assembleResult(List<ExamApplyDto> list, ExamApplyDto dto) {
        String reserve1 = "DEFAULT";
        if (ConstantsUtil.TerminalType.DEPT.getType().equals(dto.getTerminalType())) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(dto.getTerminalType()) || ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(dto.getTerminalType())) {
            for (ExamApplyDto examApplyDto : list) {
                if (StringUtils.isNotBlank(examApplyDto.getVisitDate())) {
                    Date d1 = null;
                    Date d2 = new Date();
                    try {
                        d1 = new SimpleDateFormat("yy-MM-dd").parse(examApplyDto.getVisitDate());
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    int i = DateUtil.daysOfTwo(d1, d2);
                    if (i < 0 || i > 7) {
                        continue;
                    }
                    examApplyDto.setLineColor("#FFFFE0");
                }
            }
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.SELF.getType().equals(dto.getTerminalType())) {
            reserve1 = "SELF";
        } else if (ConstantsUtil.TerminalType.MOBILE.getType().equals(dto.getTerminalType())) {
            reserve1 = "MOBILE";
        } else if (ConstantsUtil.TerminalType.SCHEDULE_CENTER.getType().equals(dto.getTerminalType())) {
            reserve1 = "CLINIC";
        } else if (ConstantsUtil.TerminalType.SCHEDULE_MANAGE.getType().equals(dto.getTerminalType())) {
            reserve1 = "CLINIC";
        }
        DictCommonUseDto dictCommonUseDto = new DictCommonUseDto();
        dictCommonUseDto.setExamClass(dto.getExamClass());
        dictCommonUseDto.setReserve1(reserve1 + ",DEFAULT");
        // 通用字段
        List<DictCommonUse> dictCommonUses = dictCommonUseService.getList(dictCommonUseDto);
        Iterator<ExamApplyDto> it = list.iterator();
        List<String> applyNos = new ArrayList<String>();
        while (it.hasNext()) {
            ExamApplyDto ea = it.next();
//            if (StringUtils.isNotBlank(dto.getScheduleStatus()) && !dto.getScheduleStatus().contains(ea.getScheduleStatus())) { // 部分查询传入状态与比较状态不符，进行此比较【!dto.getScheduleStatus().contains(ea.getScheduleStatus())】会出错
            if (StringUtils.isNotBlank(dto.getScheduleStatus())) {
                List<Boolean> removeDiscrepancies = new ArrayList<>();

                List<String> turnStatus = dto.getScheduleStatuses().stream().map(CommonUtil::turnScheduleStatus).collect(Collectors.toList());

                if (!turnStatus.contains(ea.getScheduleStatus())) {
                    removeDiscrepancies.add(true);
                }

//                dto.getScheduleStatuses().stream().forEach(item -> {
//                    String turnStatus = CommonUtil.turnStatus(item);
//                    if (!turnStatus.contains(ea.getScheduleStatus())) {
//                        removeDiscrepancies.add(true);
//                    }
//                });
                if (removeDiscrepancies.size() > 0 && !removeDiscrepancies.contains(false)) {
                    it.remove();
                }
            } else {
                String schedule = (ea.getScheduleStatus() == "2") ? "REMINDER_SCHEDULE" : "";
                // 签到提示
                String sign = (Integer.parseInt(ea.getScheduleStatus()) >= Integer.parseInt("10")) ? "REMINDER_SIGN" : "";
                StringBuffer reminder = new StringBuffer();
                StringBuffer treminder = new StringBuffer();
                StringBuffer defaultReminder = new StringBuffer();
                for (DictCommonUse dictCommonUs : dictCommonUses) {
                    if (ea.getExamClass().equals(dictCommonUs.getExamClass())) {
                        if (dictCommonUs.getName().equals(schedule)) {
                            if (reserve1.equals(dictCommonUs.getReserve1())) {
                                treminder.append(";" + dictCommonUs.getValue());
                            } else {
                                if (!dictCommonUs.getReserve1().equals("DEFAULT")) {
                                    continue;
                                }
                                defaultReminder.append(";" + dictCommonUs.getValue());
                            }
                        } else {
                            if (!dictCommonUs.getName().equals(sign)) {
                                continue;
                            }
                            if (reserve1.equals(dictCommonUs.getReserve1())) {
                                treminder.append(";" + dictCommonUs.getValue());
                            } else {
                                if (!dictCommonUs.getReserve1().equals("DEFAULT")) {
                                    continue;
                                }
                                defaultReminder.append(";" + dictCommonUs.getValue());
                            }
                        }
                    }
                }
                if (treminder.length() > 0) {
                    reminder = treminder;
                } else {
                    reminder = defaultReminder;
                }
                ea.setReminder((reminder.length() > 0) ? reminder.substring(1) : "");
                List<String> reminders = new ArrayList<String>();
                reminders.add(ea.getReminder());
                List<String> notices = new ArrayList<String>();
                notices.add(ea.getItemNotice());
                ea.setNotices(CommonUtil.convertNotice(notices, ea.getPatientSource(), (String) null, ea.getBirthDate()));
                ea.setReminders(CommonUtil.convertNotice(reminders, ea.getPatientSource(), (String) null, ea.getBirthDate()));
                ea.setSchePath(CommonUtil.convertTerminalType((ea.getSchePath() == null) ? "" : ea.getSchePath()));
                String transTool = ea.getTransTool();
                String accomExam = null;
                if (StringUtils.isNotBlank(transTool)) {
                    String[] arr = transTool.split("\\|");
                    transTool = arr[0];
                    if (arr.length >= 2) {
                        accomExam = arr[1];
                    }
                }
                ea.setTransTool(transTool);
                ea.setAccomExam(accomExam);
                applyNos.addAll(ea.getApplyNos());
                if (StringUtils.isNotBlank(dto.getPrintStatus())) {
                    ea.setPrintStatus(dto.getPrintStatus());
                }
                ea.setIndolenceFlag("0");
                ea.setClamFlag("0");
                if (!StringUtils.isNotBlank(ea.getFlags())) {
                    continue;
                }
                char[] flagsArr = ea.getFlags().toCharArray();
                ea.setIndolenceFlag(String.valueOf(flagsArr[12]));
                ea.setInfectious(String.valueOf(flagsArr[13]));
                ea.setFilingFlag(String.valueOf(flagsArr[14]));
                ea.setClamFlag(String.valueOf(flagsArr[15]));
                ea.setMultiDrug(String.valueOf(flagsArr[16]));
                ea.setBedside(String.valueOf(flagsArr[8]));
            }
        }
        if ("2".equals(dto.getQueryTag())) {
            com.rt.schedulebase.dto.DictUsersDto obj = dictUsers(dto);
            for (ExamApplyDto applyDto : list) {
                if (!ConstantsUtil.ScheduleStatus.ZERO.getStatus().equals(applyDto.getScheduleStatus())) {
                    applyDto.setTerminalType(dto.getTerminalType());
                    applyDto.setActType(ConstantsUtil.ActType.INVENTORY.getType());
                    addExamScheduleAct(applyDto, obj);
                }
            }
        }
    }

    /**
     * 获取检查项目的队列
     *
     * @param dto
     * @return
     */
    @Override
    public List<DictExamQueueDto> getQueueList(ExamApplyDto dto) {
        DictExamQueueDto dictExamQueueDto = new DictExamQueueDto();
        String hospitalCode = dto.getHospitalCode();
        // 获取指定院区的队列
        if (StringUtils.isNotBlank(dto.getIsGreenChannel())) {
            String isGreenChannel = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_SPAN_HOSPITAL_EXAM_CLASS_BY_GREEN_CHANNEL.getKey());
            if ("0".equals(isGreenChannel)) {
                hospitalCode = null;
            }
        }
        dictExamQueueDto.setHospitalCode(hospitalCode);
        dictExamQueueDto.setUseFlag("0");
        dictExamQueueDto.setClassAttr(dto.getClassAttr());
        // 跨院区检查类别
        List<String> spanHospitalExamClass = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.SPAN_HOSPITAL_EXAM_CLASS.getKey());
        if (spanHospitalExamClass.contains(dto.getExamClass()) && StringUtils.isBlank(dto.getItemCode()) && !dto.getApplyNo().startsWith("RE")) {
            dictExamQueueDto.setApplyNo(dto.getApplyNo());
            List<DictExamQueueDto> lsQueue = dictExamQueueMapper.getQueueList(dictExamQueueDto);
            if (CollectionUtils.isEmpty(lsQueue)) {
                return new ArrayList<>();
            }
            dictExamQueueDto.setExamClass(lsQueue.get(0).getExamClass());
            List<String> deptCodes = new ArrayList<>();
            for (DictExamQueue deq : lsQueue) {
                if (!deptCodes.contains(deq.getDeptCode())) {
                    deptCodes.add(deq.getDeptCode());
                }
            }
            dictExamQueueDto.setDeptCodes(deptCodes);
        } else {
            dictExamQueueDto.setExamClass(dto.getExamClass());
            if (StringUtils.isNotBlank(dto.getPerformDept())) {
                dictExamQueueDto.setDeptCode(dto.getPerformDept());
            }
        }
        if (StringUtils.isNotBlank(dto.getIsGreenChannel())) {
            dictExamQueueDto.setQueueName(dto.getQueueName());
            dictExamQueueDto.setUseFlag(null);
            dictExamQueueDto.setDeptCode(null);
        } else if (StringUtils.isNotBlank(dto.getQueueName())) {
            dictExamQueueDto.setQueueName(dto.getQueueName());
        }
        List<DictExamQueueDto> lsQueue = dictExamQueueMapper.getQueueList(dictExamQueueDto);
        return lsQueue;
    }

    /**
     * 预约计划-进行预约操作
     *
     * @param lsExamApplyDto
     * @param user
     * @param planMode
     * @param terminalType
     * @param hospitalCode
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public String getSchedulePlans(List<ExamApplyDto> lsExamApplyDto, DictUsersDto user, String planMode, String terminalType, String hospitalCode) {
        if (StringUtils.isBlank(planMode) || "0".equals(planMode)) {
            return null;
        }
        String minDate = DateUtil.getCurrDateStr();
        String maxDate = DateUtil.getCurrDateStr();
        List<ExamApplyDto> planExamApplys = new ArrayList<>();
        Map<String, List<DictExamQueueDto>> queueMap = new HashMap<>();
        Map<String, String> limitDateMap = new HashMap<>();
        List<String> itemCodes = new ArrayList<>();
        // 需要在预约前选择更新无痛标识的项目】
        String paramValue = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.EDIT_ITEM_FLAG_BEFORE_SCHEDULE.getKey());
        if (StringUtils.isNotBlank(paramValue)) {
            List<DictExamItem> itemList = JsonUtil.toList(paramValue, DictExamItem.class);
            if (itemList != null && !itemList.isEmpty()) {
                for (DictExamItem item : itemList) {
                    itemCodes.add(item.getItemCode());
                }
            }
        }
        for (ExamApplyDto ea : lsExamApplyDto) {
            if (!"2".equals(ea.getChargeFlag()) && !"3".equals(ea.getChargeFlag())) {
                // 已取消的申请单不做推荐
                if (StringUtils.isNotBlank(ea.getIsCancel())) {
                    continue;
                }
                // 只处理 未预约的申请单
                if (!"0".equals(ea.getScheduleStatus()) && !"1".equals(ea.getScheduleStatus())) {
                    continue;
                }
                boolean isFlags = true;
                for (ExamApplyItemDto dei : ea.getItems()) {
                    if (StringUtils.isBlank(dei.getFlags())) {
                        // 推荐同天-不做处理
                        if ("2".equals(planMode)) {
                            return null;
                        }
                        isFlags = false;
                        break;
                    } else {
                        // 推荐最早
                        if (itemCodes.contains(dei.getItemCode()) && "0".equals(ea.getIndolenceFlag())) {
                            isFlags = false;
                            break;
                        }
                    }
                }
                if (!isFlags) {
                    continue;
                }
                if (StringUtils.isNotBlank(hospitalCode)) {
                    ea.setHospitalCode(hospitalCode);
                }
                ExamApplyDto dto = new ExamApplyDto();
                dto.setHospitalCode(ea.getHospitalCode());
                dto.setExamClass(ea.getExamClass());
                dto.setApplyNo(ea.getApplyNo());
                dto.setPerformDept(ea.getPerformDept());
                List<DictExamQueueDto> lsQueue = getQueueList(dto);
                if (lsQueue.size() == 0) {
                    continue;
                }
                String isSchedule = isScheduleByFlags(ea.getItems(), terminalType, ea.getChargeType());
                if (StringUtils.isNotBlank(isSchedule)) {
                    continue;
                }
                boolean isGestational = false;
                if (ea.getSex() != null && ea.getSex().contains(ConstantsUtil.Gender.WOMAN.getValue())) {
                    List<ExamApplyItemDto> gestationalItems = getGestationalItems(ea.getItems());
                    if (gestationalItems.size() > 0) {
                        isGestational = true;
                        if (StringUtils.isBlank(ea.getLastMensesDate())) {
                            ea.setLastMensesDate(getLastMensesDate(ea.getSickId()));
                            if (StringUtils.isBlank(ea.getLastMensesDate())) {
                                continue;
                            }
                        }
                    }
                }
                Map<String, Integer> dateMap = getBeginDate(ea.getItems());
                ea.setBeginTime(dateMap.get("beginTime"));
                ea.setBeginDays(dateMap.get("beginDays"));
                int clamBeforesTime = configServiceImpl.getClamBeforesTime(ea.getExamClass(), CommonUtil.mergeNo2ApplyNos(ea.getMergeNo()));
                ea.setClamBeforesTime(clamBeforesTime);
                Map<String, String> queueDateMap = getBeginDateAndExpireDate(ea.getApplyNo(), ea.getHospitalCode(), ea.getPatientSource(), ea.getBeginDays());
                String startDate = queueDateMap.get("beginDate");
                String expireDate = queueDateMap.get("expireDate");
                if (isGestational) {
                    String startDate_gestational = getStartDate(ea.getLastMensesDate(), ea.getItems());
                    if (startDate_gestational.compareTo(startDate) > 0) {
                        startDate = startDate_gestational;
                    }
                    String expireDate_gestational = getExpireDate4Gestational(ea.getLastMensesDate(), ea.getItems());
                    if (StringUtils.isNotBlank(expireDate_gestational)) {
                        if (StringUtils.isNotBlank(expireDate)) {
                            if (expireDate.compareTo(expireDate_gestational) > 0) {
                                expireDate = expireDate_gestational;
                            }
                        } else {
                            expireDate = expireDate_gestational;
                        }
                    }
                }
                String currDate = DateUtil.getCurrDateStr();
                if (StringUtils.isNotBlank(startDate)) {
                    currDate = startDate;
                }
                String endDate = DateUtil.addDays2(currDate, 30);
                if (StringUtils.isNotBlank(expireDate)) {
                    endDate = expireDate;
                }
                if (currDate.compareTo(minDate) > 0) {
                    minDate = currDate;
                }
                if (endDate.compareTo(maxDate) > 0) {
                    maxDate = endDate;
                }
                String limitDate = currDate + "," + endDate;
                limitDateMap.put(ea.getMergeNo(), limitDate);
                ea.setPlanMode(planMode);
                queueMap.put(ea.getMergeNo(), lsQueue);
                // 加入到待预约的申请单
                planExamApplys.add(ea);
            }
        }
        if ("1".equals(planMode)) {
            for (ExamApplyDto ea : planExamApplys) {
                ea.setTerminalType(terminalType);
                String[] arr = limitDateMap.get(ea.getMergeNo()).split(",");
                String oldScheduleDate = ea.getScheduleDate();
                String oldScheduleApm = ea.getScheduleApm();
                Label_1538:
                for (String currDate2 = arr[0], endDate2 = arr[1]; currDate2.compareTo(endDate2) <= 0; currDate2 = DateUtil.addDays2(currDate2, 1)) {
                    ea.setUserId(user.getUserId());
                    JsonResult jsonResult = getScheduleApm(ea, currDate2);
                    if ("0".equals(jsonResult.getStatus())) {
                        List<ExamApplyDto> lsExamApply = (List<ExamApplyDto>) jsonResult.getResult();
                        for (ExamApplyDto examApplyDto : lsExamApply) {
                            ea.setOldScheduleDate(oldScheduleDate);
                            ea.setOldScheduleApm(oldScheduleApm);
                            ea.setOldQueueName(ea.getQueueName());
                            ea.setScheduledDate(ea.getScheduledDate());
                            ea.setScheduleApm(ea.getScheduleApm());
                            ea.setNewScheduleDate(currDate2);
                            ea.setNewScheduleApm(examApplyDto.getApm());
                            ea.setStartTime(examApplyDto.getStartTime());
                            ea.setEndTime(examApplyDto.getEndTime());
                            ea.setEarliestDate(ea.getNewScheduleDate());
                            ea.setEarliestTime(examApplyDto.getStartTime());
                            ea.setRegularIdList(null);
                            JsonResult result = setApm(ea, user);
                            if ("0".equals(result.getStatus())) {
                                ea.setScheduleApm(examApplyDto.getApm());
                                ea.setScheduleDate(currDate2);
                                String status = CommonUtil.turnScheduleStatus(ConstantsUtil.ScheduleStatus.ONE.getStatus());
                                ea.setScheduleStatus(status);
                                DictHospital h = dictHospitalService.getHospital(ea.getHospitalCode());
                                String hospitalName = (h.getHospitalAlias() != null) ? h.getHospitalAlias() : h.getHospitalName();
                                ea.setScheduleHospitalName(hospitalName);
                                ea.setScheduleHospital(h.getHospitalCode());
                                Map<String, String> resultMap = (Map<String, String>) result.getResult();
                                ea.setQueueName(resultMap.get("queueName"));
                                ea.setQueueAlias(resultMap.get("queueAlias"));
                                for (ExamApplyItemDto eai : ea.getItems()) {
                                    eai.setScheduleHospitalName(hospitalName);
                                    eai.setScheduleStatus(status);
                                    eai.setScheduleApm(examApplyDto.getApm());
                                    eai.setScheduleDate(currDate2);
                                }
                                break Label_1538;
                            }
                        }
                    } else {
                        ea.setScheduleDate(null);
                    }
                }
            }
        }
        Map<String, String> tempMap = new HashMap<>();
        if ("2".equals(planMode)) {
            Map<String, String> map = checkTimesHasOverlap(limitDateMap);
            if (map == null || map.size() < 1) {
                return null;
            }
            String currDate = map.get("currDate");
            String endDate = map.get("endDate");
            boolean isSameDay = false;
            while (currDate.compareTo(endDate) <= 0) {
                int planDateCount = 0;
                for (ExamApplyDto ea2 : planExamApplys) {
                    ea2.setTerminalType(terminalType);
                    ea2.setUserId(user.getUserId());
                    getOrgansOrPower(ea2);
                    ExamApplyDto ead = getScheduleDate(queueMap.get(ea2.getMergeNo()), currDate, ea2);
                    if (ead == null || !"1".equals(ead.getEnabled())) {
                        break;
                    }
                    ++planDateCount;
                }
                if (planDateCount == planExamApplys.size()) {
                    int planApmCount = 0;
                    for (ExamApplyDto examApplyDto : planExamApplys) {
                        JsonResult jsonResult2 = getScheduleApm(examApplyDto, currDate);
                        if ("0".equals(jsonResult2.getStatus())) {
                            List<ExamApplyDto> lsExamApply2 = (List<ExamApplyDto>) jsonResult2.getResult();
                            for (ExamApplyDto examApplyDto2 : lsExamApply2) {
                                examApplyDto.setOldScheduleDate(examApplyDto.getScheduleDate());
                                examApplyDto.setOldScheduleApm(examApplyDto.getScheduleApm());
                                examApplyDto.setOldQueueName(examApplyDto.getQueueName());
                                examApplyDto.setRegularIdList(null);
                                if (tempMap.get(examApplyDto.getMergeNo()) != null) {
                                    String[] arr2 = tempMap.get(examApplyDto.getMergeNo()).split(",", -1);
                                    examApplyDto.setOldScheduleDate(arr2[0]);
                                    examApplyDto.setOldScheduleApm(arr2[1]);
                                    examApplyDto.setScheduledId(arr2[2]);
                                    Double organs = StringUtils.isNotBlank(arr2[3]) ? Double.valueOf(arr2[3]) : null;
                                    examApplyDto.setOrgans(organs);
                                    examApplyDto.setNextApmRatio(arr2[4]);
                                }
                                examApplyDto.setNewScheduleDate(currDate);
                                String apm = examApplyDto2.getApm();
                                examApplyDto.setNewScheduleApm(apm);
                                examApplyDto.setStartTime(examApplyDto2.getStartTime());
                                examApplyDto.setEndTime(examApplyDto2.getEndTime());
                                JsonResult setApmResult = setApm(examApplyDto, user);
                                if ("0".equals(setApmResult.getStatus())) {
                                    examApplyDto.setScheduleApm(examApplyDto2.getApm());
                                    String scheduleStatus = CommonUtil.turnScheduleStatus(ConstantsUtil.ScheduleStatus.ONE.getStatus());
                                    examApplyDto.setScheduleStatus(scheduleStatus);
                                    DictHospital hospital = dictHospitalService.getHospital(examApplyDto.getHospitalCode());
                                    String hospitalName = (hospital.getHospitalAlias() != null) ? hospital.getHospitalAlias() : hospital.getHospitalName();
                                    examApplyDto.setScheduleHospitalName(hospitalName);
                                    examApplyDto.setScheduleHospital(hospital.getHospitalCode());
                                    for (ExamApplyItemDto applyItemDto : examApplyDto.getItems()) {
                                        applyItemDto.setScheduleHospitalName(hospitalName);
                                        applyItemDto.setScheduleStatus(scheduleStatus);
                                        applyItemDto.setScheduleApm(examApplyDto2.getApm());
                                        applyItemDto.setScheduleDate(currDate);
                                    }
                                    Map<String, String> resultMap2 = (Map<String, String>) setApmResult.getResult();
                                    examApplyDto.setQueueName(resultMap2.get("queueName"));
                                    examApplyDto.setQueueAlias(resultMap2.get("queueAlias"));
                                    String scheduledId = resultMap2.get("scheduledId");
                                    String organs2 = (resultMap2.get("organs") != null) ? resultMap2.get("organs") : "";
                                    String nextApmRatio = (resultMap2.get("nextApmRatio") != null) ? resultMap2.get("nextApmRatio") : "";
                                    tempMap.put(examApplyDto.getMergeNo(), currDate + "," + apm + "," + scheduledId + "," + organs2 + "," + nextApmRatio);
                                    ++planApmCount;
                                    break;
                                }
                            }
                        }
                    }
                    if (planApmCount == planExamApplys.size()) {
                        isSameDay = true;
                        break;
                    }
                }
                currDate = DateUtil.addDays2(currDate, 1);
            }
            if (!isSameDay) {
                for (ExamApplyDto dto2 : planExamApplys) {
                    if (StringUtils.isNotBlank(dto2.getScheduledId())) {
                        boolean isExamClass40rgan = configServiceImpl.getOrganExamClassList().contains(dto2.getExamClass());
                        ExamApplyDto ea3 = new ExamApplyDto();
                        ea3.setOrgans(dto2.getOrgans());
                        ea3.setApplyNo(dto2.getApplyNo());
                        ea3.setScheduledId(dto2.getScheduledId());
                        ea3.setMergeNo(dto2.getMergeNo());
                        ea3.setScheduleDate(dto2.getScheduleDate());
                        ea3.setRegularIdList(dto2.getRegularIdList());
                        cancelScheduleInfo(ea3, isExamClass40rgan);
                        dto2.setQueueName((String) null);
                        dto2.setScheduleHospitalName((String) null);
                        dto2.setScheduleDate((String) null);
                        dto2.setScheduleApm((String) null);
                        dto2.setScheduleStatus("0");
                    }
                }
            }
        }
        return null;
    }

    public Map<String, String> checkTimesHasOverlap(Map<String, String> limitDateMap) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Map<String, String> map = new HashMap<String, String>();
        String fixedStart = "";
        String fixedEnd = "";
        boolean isFrist = true;
        for (Object dateArr : limitDateMap.values()) {
            String[] arr = dateArr.toString().split(",");
            if (isFrist) {
                fixedStart = arr[0];
                fixedEnd = arr[1];
                isFrist = false;
                map.put("currDate", fixedStart);
                map.put("endDate", fixedEnd);
            } else {
                Date fixedStartTime = null;
                Date fixedEndTime = null;
                Date dynaStartTime = null;
                Date dynaEndTime = null;
                try {
                    fixedStartTime = sf.parse(fixedStart);
                    fixedEndTime = sf.parse(fixedEnd);
                    dynaStartTime = sf.parse(arr[0]);
                    dynaEndTime = sf.parse(arr[1]);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (dynaStartTime.getTime() >= fixedStartTime.getTime() && dynaEndTime.getTime() <= fixedEndTime.getTime()) {
                    fixedStart = sf.format(dynaStartTime.getTime());
                    fixedEnd = sf.format(dynaEndTime.getTime());
                } else if (dynaStartTime.getTime() <= fixedStartTime.getTime() && dynaEndTime.getTime() >= fixedStartTime.getTime() && dynaEndTime.getTime() <= fixedEndTime.getTime()) {
                    fixedStart = sf.format(fixedStartTime.getTime());
                    fixedEnd = sf.format(dynaEndTime.getTime());
                } else if (dynaStartTime.getTime() >= fixedStartTime.getTime() && dynaStartTime.getTime() <= fixedEndTime.getTime() && fixedEndTime.getTime() >= fixedEndTime.getTime()) {
                    fixedStart = sf.format(dynaStartTime.getTime());
                    fixedEnd = sf.format(fixedEndTime.getTime());
                } else {
                    if (dynaStartTime.getTime() > fixedStartTime.getTime() || dynaEndTime.getTime() < fixedEndTime.getTime()) {
                        return null;
                    }
                    fixedStart = sf.format(fixedStartTime.getTime());
                    fixedEnd = sf.format(fixedEndTime.getTime());
                }
                map.put("currDate", fixedStart);
                map.put("endDate", fixedEnd);
            }
        }
        return map;
    }

    public Map<String, String> getBeginDateAndExpireDate(String applyNo, String hospitalCode, String patientSource, int itemBeginDays) {
        String beginDate = DateUtil.getCurrDateStr();
        String expireDate = "";
        Integer minBeginDays = null;
        Integer maxExpireDays = null;
        DictExamQueueDto dictExamQueueDto = new DictExamQueueDto();
        dictExamQueueDto.setApplyNo(applyNo);
        dictExamQueueDto.setHospitalCode(hospitalCode);
        dictExamQueueDto.setUseFlag("0");
        List<DictExamQueueDto> queues = dictExamQueueMapper.getQueueList(dictExamQueueDto);
        if (queues != null && queues.size() > 0) {
            for (DictExamQueue queue : queues) {
                Integer beginDays = queue.getBeginDays();
                if (beginDays == null || beginDays == 0) {
                    minBeginDays = null;
                    break;
                }
                if (minBeginDays == null) {
                    minBeginDays = beginDays;
                } else {
                    if (beginDays >= minBeginDays) {
                        continue;
                    }
                    minBeginDays = beginDays;
                }
            }
            for (DictExamQueue queue : queues) {
                Integer beginDays = queue.getBeginDays();
                Integer expireDays = queue.getExpireDays();
                if (expireDays == null && itemBeginDays > 0) {
                    expireDays = itemBeginDays;
                }
                if (expireDays == null) {
                    maxExpireDays = null;
                    break;
                }
                if (itemBeginDays > 0 && itemBeginDays < expireDays) {
                    expireDays = itemBeginDays;
                }
                if (beginDays != null) {
                    expireDays += beginDays;
                }
                if (maxExpireDays == null) {
                    maxExpireDays = expireDays;
                } else {
                    if (expireDays <= maxExpireDays) {
                        continue;
                    }
                    maxExpireDays = expireDays;
                }
            }
        }
        if (minBeginDays != null) {
            beginDate = DateUtil.addDays((int) minBeginDays);
        }
        if (maxExpireDays != null) {
            expireDate = DateUtil.addDays(maxExpireDays - 1);
        }
        Map<String, String> result = new HashMap<String, String>();
        result.put("beginDate", beginDate);
        result.put("expireDate", expireDate);
        return result;
    }

    public String getStartDate(String lastMensesDate, List<ExamApplyItemDto> items) {
        int minLimit = -10000;
        for (int i = 0; i < items.size(); ++i) {
            String gestinfoDayscope = items.get(i).getGestinfoDayscope();
            if (StringUtils.isNotBlank(gestinfoDayscope)) {
                String[] arr = gestinfoDayscope.split("~");
                if (StringUtils.isNotBlank(arr[0])) {
                    int min = Integer.parseInt(arr[0]);
                    if (min > minLimit) {
                        minLimit = min;
                    }
                }
            }
        }
        if (minLimit > 0) {
            return DateUtil.addDays2(lastMensesDate, minLimit);
        }
        return DateUtil.getCurrDateStr();
    }

    public String getExpireDate4Gestational(String lastMensesDate, List<ExamApplyItemDto> items) {
        int maxLimit = 10000;
        for (int i = 0; i < items.size(); ++i) {
            String gestinfoDayscope = items.get(i).getGestinfoDayscope();
            if (StringUtils.isNotBlank(gestinfoDayscope)) {
                String[] arr = gestinfoDayscope.split("~");
                if (StringUtils.isNotBlank(arr[1])) {
                    int max = Integer.parseInt(arr[1]);
                    if (max < maxLimit) {
                        maxLimit = max;
                    }
                }
            }
        }
        if (maxLimit != 10000) {
            return DateUtil.addDays2(lastMensesDate, maxLimit);
        }
        return null;
    }

    /**
     * 获取历史申请单号
     *
     * @param dto
     * @return
     */
    public JsonResult getHisApplyByThirdUrl(ExamApplyDto dto) {
        String configByHisApply = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_GET_HIS_APPLY_BY_THIRD_WS.getKey());
        if (StringUtils.isNotBlank(configByHisApply)) {
            ConfigDto.GetHisApplyByThirdWS getHisApplyByThirdWS = JsonUtil.toBean(configByHisApply, ConfigDto.GetHisApplyByThirdWS.class);
            List<String> getHisApplyByHospitalList = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.GET_HIS_APPLY_BY_HOSPITAL.getKey());
            if (getHisApplyByThirdWS != null && "0".equals(getHisApplyByThirdWS.getGrant()) && StringUtils.isNotBlank(getHisApplyByThirdWS.getApplyUrl()) && (getHisApplyByHospitalList.isEmpty() || getHisApplyByHospitalList.contains(dto.getReqHospital()))) {
                String applyUrl = getHisApplyByThirdWS.getApplyUrl();
                ExamApplyDto examApplyDto = new ExamApplyDto();
                if (StringUtils.isNotBlank(dto.getReqDateStart())) {
                    examApplyDto.setStartDate(dto.getReqDateStart());
                } else {
                    if (StringUtils.isNotBlank(configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_VALID_DATE.getKey()))) {
                        ConfigDto.ValidDate validDate = JsonUtil.toBean(configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_VALID_DATE.getKey()), ConfigDto.ValidDate.class);
                        if ("0".equals(validDate.getGrant()) && StringUtils.isNotBlank(validDate.getValidDate())) {
                            examApplyDto.setStartDate(validDate.getValidDate());
                        }
                    }
                    if (StringUtils.isBlank(examApplyDto.getStartDate())) {
                        examApplyDto.setStartDate(DateUtil.date2Str(DateUtil.getDayBefore(new Date(), 30), DateUtil.FORMAT_DATE));
                    }
                }
                if (StringUtils.isNotBlank(dto.getReqDateEnd())) {
                    examApplyDto.setEndDate(dto.getReqDateEnd());
                } else {
                    examApplyDto.setEndDate(DateUtil.getCurrDateStr());
                }
                if (StringUtils.isNotBlank(dto.getExamClass())) {
                    examApplyDto.setExamClass(dto.getExamClass());
                }
                if (StringUtils.isNotBlank(dto.getApplyNo())) {
                    examApplyDto.setApplyNo(dto.getApplyNo());
                }
                if (StringUtils.isNotBlank(dto.getPatientSource())) {
                    examApplyDto.setPatientSource(dto.getPatientSource());
                }
                if (StringUtils.isNotBlank(dto.getInpatientNo())) {
                    examApplyDto.setInpatientNo(dto.getInpatientNo());
                }
                if (StringUtils.isNotBlank(dto.getSickId())) {
                    examApplyDto.setSickId(dto.getSickId());
                } else if (StringUtils.isNotBlank(dto.getOutpatientNo())) {
                    examApplyDto.setSickId(dto.getOutpatientNo());
                    examApplyDto.setOutpatientNo(dto.getOutpatientNo());
                } else if (StringUtils.isNotBlank(dto.getIcCard())) {
                    examApplyDto.setIcCard(dto.getIcCard());
                } else {
                    examApplyDto.setSickId(dto.getCommonCard());
                }
                String bodyContent = JsonUtil.toJson(examApplyDto);
                log.info("----------------调用第三方HIS申请单接口信息(请求地址:{},请求内容:{})-------------------", applyUrl, bodyContent);
                HttpUtil httpUtil = new HttpUtil();
                String result = httpUtil.sendHttpPostBody(applyUrl, bodyContent);
                log.info("----------------调用第三方HIS申请单接口信息(响应内容:{})-------------------", result);
                if (StringUtils.isNotBlank(result)) {
                    return JsonUtil.toBean(result, JsonResult.class);
                }
            }
        }
        return null;
    }

    public JsonResult chargeAfterSchedule(ExamApplyDto dto) {
        String chargeAfterExamClass = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CHARGE_AFTER_EXAM_CLASS.getKey());
        if (StringUtils.isNotBlank(chargeAfterExamClass)) {
            List<String> chargeAfterExamClassList = (List<String>) CommonUtil.split2List(chargeAfterExamClass);
            if (chargeAfterExamClassList.contains(dto.getExamClass())) {
                String bodyContent = JsonUtil.toJson(dto);
                String chargeUrl = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CHARGE_AFTER_SCHEDULE_URL.getKey());
                HttpUtil httpUtil = new HttpUtil();
                String result = httpUtil.sendHttpPostBody(chargeUrl, bodyContent);
                if (StringUtils.isNotBlank(result)) {
                    return (JsonResult) JsonUtil.toBean(result, (Class) JsonResult.class);
                }
            }
        }
        return null;
    }

    /**
     * 报到成功后进行扣费 - 调用第三方扣费接口
     *
     * @param dto
     * @return
     */
    public JsonResult chargeAfterSign(ExamApplyDto dto) {
        String chargeAfterExamClassBySign = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CHARGE_AFTER_EXAM_CLASS_BY_SIGN.getKey());
        if (StringUtils.isNotBlank(chargeAfterExamClassBySign)) {
            List<String> chargeAfterExamClassBySignList = CommonUtil.split2List(chargeAfterExamClassBySign);
            if (chargeAfterExamClassBySignList.contains(dto.getExamClass())) {
                String bodyContent = JsonUtil.toJson(dto);
                String chargeUrl = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CHARGE_AFTER_SIGN_URL.getKey());
                HttpUtil httpUtil = new HttpUtil();
                String result = httpUtil.sendHttpPostBody(chargeUrl, bodyContent);
                if (StringUtils.isNotBlank(result)) {
                    return JsonUtil.toBean(result, JsonResult.class);
                }
            }
        }
        return null;
    }

    public JsonResult confirmFeeBeforeSchedule(ExamApplyDto dto, String actType, DictUsersDto dictUsers) {
        if (configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_CONFIRM_FEE_BEFORE_SCHEDULE.getKey())) {
            String confirmFeeScheduleUrl = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SCHEDULE_URL.getKey());
            if (!StringUtils.isNotBlank(confirmFeeScheduleUrl)) {
                return JsonResultUtil.failure("预约系统已启用确认预约时确费设置，但还没有配置确费调用链接，请联系管理员设置！");
            }
            List<String> confirmFeeScheduleExamClassList = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SCHEDULE_EXAM_CLASS.getKey());
            List<String> confirmFeeSchedulePatientSource = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SCHEDULE_PATIENT_SOURCE.getKey());
            boolean isConfirmFeeSchedule = false;
            if (!confirmFeeScheduleExamClassList.isEmpty() && !confirmFeeSchedulePatientSource.isEmpty()) {
                isConfirmFeeSchedule = (confirmFeeScheduleExamClassList.contains(dto.getExamClass()) && confirmFeeSchedulePatientSource.contains(dto.getPatientSource()));
            } else if (!confirmFeeScheduleExamClassList.isEmpty()) {
                isConfirmFeeSchedule = confirmFeeScheduleExamClassList.contains(dto.getExamClass());
            } else {
                isConfirmFeeSchedule = (confirmFeeSchedulePatientSource.isEmpty() || confirmFeeSchedulePatientSource.contains(dto.getPatientSource()));
            }
            if (isConfirmFeeSchedule) {
                List<String> applyNos = (List<String>) CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
                if (applyNos.isEmpty()) {
                    applyNos.add(dto.getApplyNo());
                }
                dto.setApplyNos(applyNos);
                dto.setActType(actType);
                dto.setUserId(dictUsers.getUserId());
                dto.setStaffNo(dictUsers.getStaffNo());
                dto.setUserName(dictUsers.getName());
                String bodyContent = JsonUtil.toJson(dto);
                String timeout = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.HTTP_TIMEOUT.getKey());
                log.info("----------------确认预约时确费(请求地址:{},请求内容:{})-------------------", confirmFeeScheduleUrl, bodyContent);
                String result = "";
                try {
                    HttpUtil httpUtil = new HttpUtil();
                    result = httpUtil.sendHttpPostBody(confirmFeeScheduleUrl, bodyContent, timeout);
                } catch (ResourceAccessException r) {
                    throw new AccountException("确认预约时确费超时");
                }
                log.info("----------------确认预约时确费(响应内容:{})-------------------", result);
                if (!StringUtils.isNotBlank(result)) {
                    return JsonResultUtil.failure("确认预约时确费失败");
                }
                JsonResult jsonResult = (JsonResult) JsonUtil.toBean(result, (Class) JsonResult.class);
                if (!"0".equals(jsonResult.getStatus())) {
                    return JsonResultUtil.failure(jsonResult.getMessage());
                }
                return jsonResult;
            }
        }
        return null;
    }

    /**
     * 报道时确费
     *
     * @param dto
     * @param actType
     * @param dictUsers
     * @return
     */
    public JsonResult confirmFeeBeforeSign(ExamApplyDto dto, String actType, DictUsersDto dictUsers) {
        if (configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_CONFIRM_FEE_BEFORE_SIGN.getKey())) {
            String confirmFeeSignUrl = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SIGN_URL.getKey());
            if (!StringUtils.isNotBlank(confirmFeeSignUrl)) {
                String msg = "预约系统已启用报到时确费设置，但还没有配置确费调用链接，请联系管理员设置！";
                log.error(msg);
                return JsonResultUtil.failure(msg);
            }
            List<String> confirmFeeSignExamClassList = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SIGN_EXAM_CLASS.getKey());
            List<String> confirmFeeSignPatientSource = configServiceImpl.getConfigListByName(ConstantsUtil.ConfigName.CONFIRM_FEE_BEFORE_SIGN_PATIENT_SOURCE.getKey());
            boolean isConfirmFeeSign = false;
            if (!confirmFeeSignExamClassList.isEmpty() && !confirmFeeSignPatientSource.isEmpty()) {
                isConfirmFeeSign = (confirmFeeSignExamClassList.contains(dto.getExamClass()) && confirmFeeSignPatientSource.contains(dto.getPatientSource()));
            } else if (!confirmFeeSignExamClassList.isEmpty()) {
                isConfirmFeeSign = confirmFeeSignExamClassList.contains(dto.getExamClass());
            } else {
                isConfirmFeeSign = (confirmFeeSignPatientSource.isEmpty() || confirmFeeSignPatientSource.contains(dto.getPatientSource()));
            }
            if (isConfirmFeeSign) {
                List<String> applyNos = (List<String>) CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
                if (applyNos.isEmpty()) {
                    applyNos.add(dto.getApplyNo());
                }
                dto.setApplyNos(applyNos);
                dto.setActType(actType);
                dto.setUserId(dictUsers.getStaffNo());
                dto.setUserName(dictUsers.getName());
                String bodyContent = JsonUtil.toJson(dto);
                log.info("----------------报到时确费(请求地址:{},请求内容:{})-------------------", confirmFeeSignUrl, bodyContent);
                HttpUtil httpUtil = new HttpUtil();
                String result = httpUtil.sendHttpPostBody(confirmFeeSignUrl, bodyContent);
                log.info("----------------报到时确费(响应内容:{})-------------------", result);
                if (!StringUtils.isNotBlank(result)) {
                    return JsonResultUtil.failure("计费服务连接失败（无法报道）请联系信息科！");
                }
                JsonResult jsonResult = (JsonResult) JsonUtil.toBean(result, (Class) JsonResult.class);
                if (!"0".equals(jsonResult.getStatus())) {
                    return JsonResultUtil.failure(jsonResult.getMessage());
                }
                return jsonResult;
            }
        }
        return null;
    }

    public JsonResult recedeCost(ExamApplyDto dto, String actType, com.rt.schedulebase.dto.DictUsersDto dictUsers) {
        dto.setUserId(dictUsers.getStaffNo());
        dto.setUserName(dictUsers.getName());
        List<String> applyNos = (List<String>) CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
        if (applyNos.isEmpty()) {
            applyNos.add(dto.getApplyNo());
        }
        if (ConstantsUtil.ActType.CANCEL.getType().equals(actType)) {
            String isRecedeCostByCancel = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_RECEDE_COST_BY_CANCEL.getKey());
            if (StringUtils.isNotBlank(isRecedeCostByCancel)) {
                ConfigDto.RecedeCostByCancel recedeCostByCancel = JsonUtil.toBean(isRecedeCostByCancel, ConfigDto.RecedeCostByCancel.class);
                if (recedeCostByCancel != null && "0".equals(recedeCostByCancel.getGrant())) {
                    dto.setApplyNos(applyNos);
                    dto.setActType(actType);
                    String bodyContent = JsonUtil.toJson(dto);
                    String recedeCostUrl = recedeCostByCancel.getRecedeCostUrl();
                    if (!StringUtils.isNotBlank(recedeCostUrl)) {
                        return JsonResultUtil.failure("预约系统已启用取消预约调用退费设置，但还没有配置退费调用链接，请联系管理员设置");
                    }
                    log.info("----------------取消预约退费(请求地址:{},请求内容:{})-------------------", recedeCostUrl, bodyContent);
                    HttpUtil httpUtil = new HttpUtil();
                    String result = httpUtil.sendHttpPostBody(recedeCostUrl, bodyContent);
                    log.info("----------------取消预约退费(响应内容:{})-------------------", result);
                    if (!StringUtils.isNotBlank(result)) {
                        return JsonResultUtil.failure("取消预约时退费超时");
                    }
                    JsonResult jsonResult = (JsonResult) JsonUtil.toBean(result, (Class) JsonResult.class);
                    if (!"0".equals(jsonResult.getStatus())) {
                        return JsonResultUtil.failure("取消预约时退费失败，失败原因：" + jsonResult.getMessage());
                    }
                    return jsonResult;
                }
            }
        } else {
            String isRecedeCostByReSet = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.IS_RECEDE_COST_BY_RESET.getKey());
            if (StringUtils.isNotBlank(isRecedeCostByReSet)) {
                ConfigDto.RecedeCostByReSet recedeCostByReSet = JsonUtil.toBean(isRecedeCostByReSet, ConfigDto.RecedeCostByReSet.class);
                if (recedeCostByReSet != null && "0".equals(recedeCostByReSet.getGrant())) {
                    ExamsDto examsDto = new ExamsDto();
                    examsDto.setApplyNos(applyNos);
                    List<Exams> examsList = (List<Exams>) examsService.selectList(examsDto);
                    List<String> examNos = new ArrayList<String>();
                    if (examsList != null && !examsList.isEmpty()) {
                        for (Exams exams : examsList) {
                            if (!examNos.contains(exams.getExamNo())) {
                                examNos.add(exams.getExamNo());
                            }
                        }
                    }
                    dto.setExamNos(examNos);
                    dto.setApplyNos(applyNos);
                    dto.setActType(actType);
                    String bodyContent2 = JsonUtil.toJson(dto);
                    String recedeCostUrl2 = recedeCostByReSet.getRecedeCostUrl();
                    if (!StringUtils.isNotBlank(recedeCostUrl2)) {
                        return JsonResultUtil.failure("预约系统已启用取消报到调用退费设置，但还没有配置退费调用链接，请联系管理员设置！");
                    }
                    log.info("----------------取消报到退费(请求地址:{},请求内容:{})-------------------", recedeCostUrl2, bodyContent2);
                    HttpUtil httpUtil2 = new HttpUtil();
                    String result2 = httpUtil2.sendHttpPostBody(recedeCostUrl2, bodyContent2);
                    log.info("----------------取消报到退费(响应内容:{})-------------------", result2);
                    if (!StringUtils.isNotBlank(result2)) {
                        return JsonResultUtil.failure("取消报到时退费超时");
                    }
                    JsonResult jsonResult2 = (JsonResult) JsonUtil.toBean(result2, (Class) JsonResult.class);
                    if (!"0".equals(jsonResult2.getStatus())) {
                        return JsonResultUtil.failure("取消报到时退费失败，失败原因：" + jsonResult2.getMessage());
                    }
                    return jsonResult2;
                }
            }
        }
        return null;
    }

    /**
     * 检查预约项目是否可以正常操作
     *
     * @param itemsAll
     * @param terminalType
     * @param chargeType
     * @return
     */
    public String isScheduleByFlags(List<ExamApplyItemDto> itemsAll, String terminalType, String chargeType) {
        if (itemsAll != null) {
            String strReturn = "您的检查申请单暂不支持预约！";
            String itemStr = configServiceImpl.customReminder(ConstantsUtil.ConfigName.NO_SCHEDULE_ITEM_REMINDER.getKey(), "", "");
            if (StringUtils.isNotBlank(itemStr)) {
                strReturn = itemStr;
            }
            // 限制预约终端项目
            String limitTerminalItemStr = configServiceImpl.customReminder(ConstantsUtil.ConfigName.LIMIT_SCHEDULE_ITEM_BY_TERMINAL_REMINDER.getKey(), "", "");
            for (ExamApplyItemDto examApplyItemDto : itemsAll) {
                String flag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 1);

                //
                if ("2".equals(flag) && !ConstantsUtil.TerminalType.SCHEDULE_MANAGE.getType().equals(terminalType) && !ConstantsUtil.TerminalType.DEPT.getType().equals(terminalType) && !ConstantsUtil.TerminalType.SCHEDULE_CENTER.getType().equals(terminalType)) {
                    strReturn = "该项目不支持自助";
                    if (StringUtils.isNotBlank(limitTerminalItemStr)) {
                        strReturn = limitTerminalItemStr;
                    } else if (StringUtils.isNotBlank(itemStr)) {
                        strReturn = itemStr;
                    }
                    return strReturn;
                }
                if ("1".equals(flag)) {
                    return strReturn;
                }
                flag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 8);
                if ("1".equals(flag) && ConstantsUtil.TerminalType.SCHEDULE_CENTER.getType().equals(terminalType)) {
                    return strReturn;
                }

                flag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 9);
                boolean isClinic = "1".equals(flag) && (ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(terminalType) || ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(terminalType));
                boolean isClinicOut = "2".equals(flag) && ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(terminalType);
                boolean isClinicHospital = "3".equals(flag) && ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(terminalType);
                if (isClinic || isClinicOut || isClinicHospital) {
                    if (StringUtils.isNotBlank(limitTerminalItemStr)) {
                        strReturn = limitTerminalItemStr;
                    }
                    return strReturn;
                }
                flag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 10);
                if ("1".equals(flag) && ConstantsUtil.TerminalType.SELF.getType().equals(terminalType)) {
                    if (StringUtils.isNotBlank(limitTerminalItemStr)) {
                        strReturn = limitTerminalItemStr;
                    }
                    return strReturn;
                }
                flag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 11);
                if ("1".equals(flag) && ConstantsUtil.TerminalType.MOBILE.getType().equals(terminalType)) {
                    if (StringUtils.isNotBlank(limitTerminalItemStr)) {
                        strReturn = limitTerminalItemStr;
                    }
                    return strReturn;
                }
            }
        }
        return "";
    }

    /**
     * 获取申请单缴费状态
     *
     * @param dto
     * @return 0 未缴费 1 已缴费
     */
    public String getChargeFlag(ExamApplyDto dto) {
        String chargeFlag = dto.getChargeFlag();
        if (configServiceImpl.isOpenConfig(ConstantsUtil.ConfigName.IS_GET_CHARGE_FLAG_REALTIME.getKey())) {
            String chargeFlagRealTimeUrl = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.GET_CHARGE_FLAG_REALTIME_URL.getKey());
            if (StringUtils.isNotBlank(chargeFlagRealTimeUrl)) {
                List<String> applyNos = CommonUtil.mergeNo2ApplyNos(dto.getMergeNo());
                if (applyNos.isEmpty()) {
                    applyNos.add(dto.getApplyNo());
                }
                dto.setApplyNos(applyNos);
                String bodyContent = JsonUtil.toJson(dto);
                String timeout = configServiceImpl.getConfigByName(ConstantsUtil.ConfigName.HTTP_TIMEOUT.getKey());
                log.info("----------------实时获取缴费标识(请求地址:{},请求内容:{})-------------------", chargeFlagRealTimeUrl, bodyContent);
                HttpUtil httpUtil = new HttpUtil();
                String result = "";
                try {
                    result = httpUtil.sendHttpPostBody(chargeFlagRealTimeUrl, bodyContent, timeout);
                } catch (ResourceAccessException r) {
                    throw new AccountException("获取缴费标识超时");
                }
                log.info("----------------实时获取缴费标识(响应内容:{})-------------------", result);
                if (StringUtils.isNotBlank(result)) {
                    JsonResult jsonResult = JsonUtil.toBean(result, JsonResult.class);
                    if (jsonResult != null && "0".equals(jsonResult.getStatus())) {
                        JSONObject json = (JSONObject) jsonResult.getResult();
                        ExamApplyDto examApplyDto = json.toJavaObject(ExamApplyDto.class);
                        return examApplyDto.getChargeFlag();
                    }
                }
            }
        }
        return StringUtils.isNotBlank(chargeFlag) ? chargeFlag : "0";
    }

    /**
     * @param examClass
     * @param hospitalCode
     * @param itemCode
     * @return
     * @description 获取执行的科室编码和检查项目、检查类别
     * @author ryan.li
     * @date 2022/10/21 11:29
     */
    public Map<String, Object> getPerformDeptCodeAndExamClassAndItems(String examClass, String hospitalCode, String itemCode) {
        String[] itemCodes = itemCode.split(",");
        List<DictExamItemDto> items = new ArrayList<>();
        int item_cnt = 0;
        List<String> list = new ArrayList<>();

        for (String str : itemCodes) {
            DictExamItemDto e = new DictExamItemDto();
            e.setItemCode(str);
            items.add(e);
            if (!list.contains(str)) {
                list.add(str);
                ++item_cnt;
            }
        }
        // 获取检查类别的队列
        DictExamQueueDto dictExamQueueDto = new DictExamQueueDto();
        dictExamQueueDto.setExamClass(examClass);
        dictExamQueueDto.setHospitalCode(hospitalCode);
        List<DictExamQueueDto> queues = dictExamQueueMapper.getQueueList(dictExamQueueDto);
        if (CollectionUtils.isNotEmpty(queues)) {
            DictScheduleApmDto dictScheduleApmDto = new DictScheduleApmDto();
            dictScheduleApmDto.setQueues(queues);
            List<DictScheduleApmDto> commonScheduleApm = dictScheduleApmMapper.getCommonScheduleApm(dictScheduleApmDto);
            List<DictScheduleApmDto> dateScheduleApm = dictScheduleApmMapper.getDateScheduleApm(dictScheduleApmDto);
            List<DictScheduleApmDto> weekScheduleApm = dictScheduleApmMapper.getWeekScheduleApm(dictScheduleApmDto);

            if (CollectionUtils.isEmpty(commonScheduleApm)
                    && CollectionUtils.isEmpty(dateScheduleApm)
                    && CollectionUtils.isEmpty(weekScheduleApm)) {
                log.error("队列下没有时段");
                return null;
            }
            DictExamQueue queue = queues.stream()
                    .filter(deq -> deq.getExamClass().equals(examClass))
                    .findFirst().orElse(new DictExamQueueDto());

            DictExamItemDto dictExamItemDto = new DictExamItemDto();
            dictExamItemDto.setExamClass(examClass);
            dictExamItemDto.setItems(items);
            // 获取检查项目信息
            items = dictExamItemMapper.selectItemList(dictExamItemDto);
            if (item_cnt == items.size()) {
                Map<String, Object> result = new HashMap<>();
                // 诊室编码
                result.put("performDeptCode", queue.getDeptCode());
                result.put("performDeptName", "");
                // 检查类别
                result.put("examClass", queue.getExamClass());
                List<ExamApplyItemDto> lsItem = new ArrayList<>();
                for (int i = 0; i < items.size(); ++i) {
                    ExamApplyItemDto examApplyItemDto = new ExamApplyItemDto();
                    examApplyItemDto.setExamClass(items.get(i).getExamClass());
                    examApplyItemDto.setExamSubClass(items.get(i).getExamSubClass());
                    examApplyItemDto.setItemCode(items.get(i).getItemCode());
                    examApplyItemDto.setItemName(items.get(i).getItemName());
                    examApplyItemDto.setItemNo(Long.parseLong(String.valueOf(i + 1)));
                    examApplyItemDto.setOrgans((items.get(i).getOrgans() == null) ? 1.0 : items.get(i).getOrgans());
                    examApplyItemDto.setFlags(items.get(i).getFlags());
                    examApplyItemDto.setScheduleOrder(items.get(i).getScheduleOrder());
                    examApplyItemDto.setGestinfoDayscope(items.get(i).getGestinfoDayscope());
                    lsItem.add(examApplyItemDto);
                }
                // 检查项目信息
                result.put("items", lsItem);
                return result;
            }
            log.error("该院区不能检查这些项目");
        } else {
            log.error("根据检查类别和院区代码找不到队列");
        }
        return null;
    }

    /**
     * 获取预约申请的签到时间
     * 判断签到时间是否 在开始时间和结束时间范围内
     * isStartTime 是否早于最早报到时间 true 是
     * isEndTime 是否晚于最晚报到时间 true 是
     * timeEarliest 最早签到时间 HH:mm:ss
     * dateEarliest 最早签到日期 yyyy-MM-dd
     * timeSignin 最晚签到
     * dateTimeSignEarliest 最早签到时间日期
     *
     * @param ea
     * @return
     */
    @Override
    public Map<String, Object> judgeTimeSignin(ExamApplyDto ea) {
        Map<String, Object> resultMap = new HashMap<>();

        // 获取时段信息
        QueryWrapper<DictScheduleApm> query = new QueryWrapper<>();
        query.eq("APM_CODE", ea.getApmCode());
        DictScheduleApm apm = dictScheduleApmMapper.selectOne(query);

        String earliestTimeSign = StringUtils.isBlank(apm.getTimeEarliest()) ? "00:00:00" : apm.getTimeEarliest();
        String lastTimeSign = apm.getTimeSignin();
        String currentDateTime = DateUtil.getCurrentDateTime();
        String dateEarliest = ea.getScheduleDate();
        // 预约 最早报到时间
        String dateTimeSignEarliest = ea.getScheduleDate() + " " + earliestTimeSign;
        // 如果  预约 最早报到时间 不为空 且提前天数大于0 重新计算签到时间
        if (Objects.nonNull(apm.getDaysEarliest()) && Objects.nonNull(apm.getDaysEarliest()) && apm.getDaysEarliest() > 0) {
            dateEarliest = DateUtil.addDays2(ea.getScheduleDate(), -apm.getDaysEarliest());
            dateTimeSignEarliest = dateEarliest + " " + earliestTimeSign;
        }
        // 最晚报到时间
        String dateTimeSignLatest = ea.getScheduleDate() + " " + lastTimeSign;
        if (StringUtils.isNotBlank(apm.getDaysSignin()) && !"0".equals(apm.getDaysSignin())) {
            String dateSignLatest = DateUtil.addDays2(ea.getScheduleDate(), -Integer.parseInt(apm.getDaysSignin()));
            dateTimeSignLatest = dateSignLatest + " " + lastTimeSign;
        }
        boolean isStartTime = false;
        boolean isEndTime = false;

        long nowDateTime = DateUtil.parse(currentDateTime, DateUtil.FORMAT_DATETIME).getTime();
        long startTime = DateUtil.parse(dateTimeSignEarliest, DateUtil.FORMAT_DATETIME).getTime();
        long endTime = DateUtil.parse(dateTimeSignLatest, DateUtil.FORMAT_DATETIME).getTime();

        if (nowDateTime <= startTime) {
            isStartTime = true;
        }
        if (nowDateTime >= endTime) {
            isEndTime = true;
        }
        resultMap.put("timeEarliest", earliestTimeSign);
        resultMap.put("timeSignin", lastTimeSign);
        resultMap.put("isStartTime", isStartTime);
        resultMap.put("isEndTime", isEndTime);
        resultMap.put("dateEarliest", dateEarliest);
        resultMap.put("dateTimeSignEarliest", dateTimeSignEarliest);
        resultMap.put("dateTimeSignLatest", dateTimeSignLatest);
        return resultMap;
    }

    /**
     * 获取申请单信息
     *
     * @param applyNo
     * @param terminalType
     * @return
     */
    @Override
    public ExamApplyDto getExamApplyInfo(String applyNo, String terminalType) {
        ExamApplyDto ea;
        if (applyNo.startsWith("RE")) {
            ea = examReferMapper.findByApplyNo(applyNo);
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("applyNo", applyNo);
            map.put("terminalType", terminalType);
            ea = examApplyMapper.getExamApply(map);
        }
        return ea;
    }

    /**
     * 获取占号数量
     *
     * @param ea
     */
    public void getOrgansOrPower(ExamApplyDto ea) {
        // 【按项目预约量系数占号的检查类别】(多个用英文逗号“,”分隔)
        boolean isExamClass4Organ = configServiceImpl.getOrganExamClassList().contains(ea.getExamClass());
        double reqCount = 1.0;
        if (isExamClass4Organ) {
            reqCount = getReqOrganByItems(ea.getItems());
        }
        ea.setIsExamClass4Organ(isExamClass4Organ);
        ea.setReqCount(reqCount);
        DictUsersDto userDto = dictUsers(ea);
        boolean isCancelPower = false;
        if (StringUtils.isNotBlank(userDto.getUserId())) {
            DictRoleFunctionDto functionDto = new DictRoleFunctionDto();
            functionDto.setUserId(userDto.getUserId());
            functionDto.setExamClass(ea.getExamClass());
            int i = dictRoleFunctionService.getCount(functionDto);
            if (i > 0) {
                isCancelPower = true;
            }
        }
        ea.setIsCancelPower(isCancelPower);
    }

    /***
     * 保存检查信息引用
     * @param examApply
     * @param queueName
     * @return
     */
    public int saveRefer(ExamApplyDto examApply, String queueName) {
        ExamRefer examRefer = new ExamRefer();
        examRefer.setApplyId(examApply.getApplyNo());
        examRefer.setSickId(examApply.getSickId());
        examRefer.setIcCard(examApply.getIcCard());
        examRefer.setOutpatientNo(examApply.getOutpatientNo());
        examRefer.setInpatientNo(examApply.getInpatientNo());
        examRefer.setPatientSource(examApply.getPatientSource());
        examRefer.setIdentityCard(examApply.getIdentityCard());
        examRefer.setName(examApply.getName());
        examRefer.setScheduledDate(examApply.getScheduleDate());
        examRefer.setScheduleApm(examApply.getScheduleApm());
        examRefer.setExamClass(examApply.getExamClass());
        examRefer.setPhoneNumber(examApply.getPhoneNumber());
        examRefer.setSex(examApply.getSex());
        examRefer.setAge(examApply.getAge());
        examRefer.setBirthDate(examApply.getBirthDate());
        examRefer.setReqHospitalCode(examApply.getReqHospital());
        examRefer.setReqDept(examApply.getReqDept());
        examRefer.setApplicantCode(examApply.getUserId());
        examRefer.setApplicantName(examApply.getUserName());
        examRefer.setReqDate(DateUtil.getCurrDateStr());
        examRefer.setReqTime(DateUtil.getCurrentTime());
        examRefer.setHospitalCode(examApply.getHospitalCode());
        examRefer.setHospitalName(examApply.getHospitalName());
        examRefer.setLastMensesDate(examApply.getLastMensesDate());
        examRefer.setPregnancyWeeks(examApply.getWeeks());
        examRefer.setPriorityOrder(examApply.getPriorityOrder());
        examRefer.setScheduleStatus("08");
        examRefer.setQueueName(queueName);
        examRefer.setScheduleMemo(examApply.getMemo());
        if (StringUtils.isNotBlank(examApply.getReqReachTime())) {
            String[] reqReachDateArr = examApply.getReqReachTime().split(" ");
            examRefer.setReqReachDate(reqReachDateArr[0]);
            examRefer.setReqReachTime(reqReachDateArr[1]);
        }
        int i = examReferService.insert(examRefer);

        for (ExamApplyItemDto item : examApply.getItems()) {
            ExamReferItem examReferItem = new ExamReferItem();
            examReferItem.setApplyId(item.getApplyNo());
            examReferItem.setItemNo(item.getItemNo());
            examReferItem.setItemCode(item.getItemCode());
            examReferItem.setItemName(item.getItemName());
            examReferItem.setAmount(1);
            i = examReferItemService.insert(examReferItem);
        }
        return i;
    }

    public boolean isAllNotScheduleItems(List<ExamApplyItemDto> itemsAll) {
        if (itemsAll != null) {
            for (ExamApplyItemDto examApplyItemDto : itemsAll) {
                if (!"1".equals(examApplyItemDto.getUnschedule())) {
                    return false;
                }
                String unscheduleFlag = CommonUtil.subFlags(examApplyItemDto.getFlags(), 1);
                if (!"1".equals(unscheduleFlag)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * @param items
     * @return true 包含 false 不包含
     * @description 检查项目里面是否包含 孕期限制的检查项目
     * @author ryan.li
     * @date 2022/11/9 9:44
     */
    public boolean isGestationalApply(List<ExamApplyItemDto> items) {
        for (ExamApplyItemDto item : items) {
            String gestinfoDayscope = item.getGestinfoDayscope();
            if (StringUtils.isNotBlank(gestinfoDayscope)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public ExamApplyDto getApplyForScheduleItem(ExamApplyDto dto) {
        if (StringUtils.isNotBlank(dto.getApplyNo())) {
            dto.setApplyNo(dto.getApplyNo().split(",")[0]);
        }
        ExamApplyDto ea = getExamApplyInfo(dto.getApplyNo(), dto.getTerminalType());

        if (ea == null) {
            ea = new ExamApplyDto();
            ea.setDesc("您的检查申请单信息不存在，如有疑问请到护士站咨询！");
            return ea;
        }
        String mergeNos = StringUtils.isBlank(dto.getMergeNo()) ? "" : dto.getMergeNo();
        ea.setClassAttr(dto.getClassAttr());
        List<ExamApplyItemDto> items = getExamApplyItem(mergeNos, ea);
        if (items.size() == 0) {
            ea.setDesc("您的检查项目单不存在，如有疑问请到护士站咨询！");
            return ea;
        }
        List<String> itemCodes = new ArrayList<>();
        StringBuffer mergeNosSB = new StringBuffer();
        for (ExamApplyItemDto item : items) {
            if (!ConstantsUtil.ActType.CANCEL.getType().equals(dto.getActType()) && StringUtils.isBlank(item.getFlags())) {
                ea.setDesc("您的检查申请单项目未维护,暂不支持操作！");
                return ea;
            }
            itemCodes.add(item.getItemCode());
            mergeNosSB.append("," + dto.getApplyNo() + "-" + item.getItemNo());
        }
        if (StringUtils.isBlank(mergeNos)) {
            mergeNos = mergeNosSB.substring(1);
        }
        Map<String, Object> mapGroup = new HashMap<>();
        mapGroup.put("examClass", ea.getExamClass());
        mapGroup.put("itemCodes", itemCodes);
        mapGroup.put("patientSource", ea.getPatientSource());
        boolean isItemOrder = true;
        // 查询检查项目分组信息
        List<DictItemGroupDetailDto> digs = dictItemGroupMapper.getGroupForOrder(mapGroup);
        for (ExamApplyItemDto item : items) {
            for (DictItemGroupDetailDto dig : digs) {
                if (item.getItemCode().equals(dig.getItemCode()) && dig.getScheduleOrder() != null) {
                    item.setScheduleOrderGroup(dig.getScheduleOrder());
                    isItemOrder = false;
                }
            }
        }
        collectionSort(items, isItemOrder);
        ea.setItems(items);
        ea.setMergeNo(mergeNos);
        boolean isExamClass4Organ = configServiceImpl.getOrganExamClassList().contains(ea.getExamClass());
        Double reqCount = 1.0;
        if (isExamClass4Organ) {
            reqCount = getOrgansReqCount(ea);
            if (reqCount == null) {
                reqCount = getReqOrganByItems(ea.getItems());
            }
        }
        ea.setReqCount(reqCount);
        ea.setIsExamClass4Organ(isExamClass4Organ);
        return ea;
    }

    public WaitingDto getWaitingInfo(ExamApplyDto ea) {
        String examNo = ea.getExamNo();
        Map<String, String> map = new HashMap<String, String>();
        map.put("examNo", examNo);
        map.put("result", "");
        map.put("desc", "");
        examQueueMapper.getWaitingInfo(map);
        String result = map.get("result");
        String desc = map.get("desc");
        log.info("获取候诊信息:{}   {} ", result, desc);
        WaitingDto wait = new WaitingDto();
        if (!"-1".equals(result) && StringUtils.isNotBlank(result)) {
            Map<String, String> m = CommonUtil.stringToMap(result);
            String queueName = m.get("queue_name");
            String queueNo = m.get("queue_no");
            String currentQueueNo = m.get("current_queue_no");
            String waitingCnt = m.get("waiting_cnt");
            String jzWaitingCnt = m.get("jz_waiting_cnt");
            String zhWaitingCnt = m.get("zh_waiting_cnt");
            String waitingTime = m.get("waiting_time");
            String jzWaitingTime = m.get("jz_waiting_cnt");
            String zhWaitingTime = m.get("zh_waiting_cnt");
            String unsignCnt = m.get("unsign_cnt");
            wait.setQueueName(StringUtils.isNotBlank(queueName) ? queueName : "");
            wait.setQueueNo(StringUtils.isNotBlank(queueNo) ? queueNo : "");
            wait.setCurrentQueueNo(StringUtils.isNotBlank(currentQueueNo) ? currentQueueNo : "");
            wait.setWaitingCnt(StringUtils.isNotBlank(waitingCnt) ? Integer.parseInt(waitingCnt) : 0);
            wait.setJzWaitingCnt(StringUtils.isNotBlank(jzWaitingCnt) ? Integer.parseInt(jzWaitingCnt) : 0);
            wait.setZhWaitingCnt(StringUtils.isNotBlank(zhWaitingCnt) ? Integer.parseInt(zhWaitingCnt) : 0);
            wait.setWaitingTime(StringUtils.isNotBlank(waitingTime) ? Integer.parseInt(waitingTime) : 0);
            wait.setJzWaitingTime(StringUtils.isNotBlank(jzWaitingTime) ? Integer.parseInt(jzWaitingTime) : 0);
            wait.setZhWaitingTime(StringUtils.isNotBlank(zhWaitingTime) ? Integer.parseInt(zhWaitingTime) : 0);
            wait.setUnsignCnt(StringUtils.isNotBlank(unsignCnt) ? Integer.parseInt(unsignCnt) : 0);
            ExamApplyItemDto examItem = new ExamApplyItemDto();
            examItem.setExamNo(examNo);
            examItem.setExamClass(ea.getExamClass());
            List<ExamApplyItemDto> items = examItemMapper.findExamItemsByExamNo(examItem);
            List<String> notices = new ArrayList<String>();
            for (int i = 0; i < items.size(); ++i) {
                if (StringUtils.isNotBlank(items.get(i).getNotice())) {
                    String[] split;
                    String[] array = split = items.get(i).getNotice().split("\\|");
                    for (String n : split) {
                        if (!notices.contains(n)) {
                            notices.add(n);
                        }
                    }
                }
            }
            wait.setNotices(notices);
        }
        return wait;
    }

    public String hasNoSignSelfItem(List<ExamApplyItemDto> items) {
        for (ExamApplyItemDto item : items) {
            if (StringUtils.isNotBlank(item.getFlags())) {
                String selfSignFlag = CommonUtil.subFlags(item.getFlags(), 7);
                if (!"0".equals(selfSignFlag)) {
                    return "有不允许自助报到的项目[" + item.getItemName() + "]";
                }
            }
        }
        return null;
    }

    /**
     * 获取检查类别的属性
     *
     * @param examClass
     * @return
     */
    public Integer getClassAttr(String examClass) {
        DictExamClassDto dictExamClassDto = new DictExamClassDto();
        dictExamClassDto.setExamClassName(examClass);
        List<DictExamClass> list = dictExamClassService.getList(dictExamClassDto);
        if (list != null && list.size() > 0) {
            String classAttr = list.get(0).getClassAttr();
            return (classAttr != null) ? Integer.parseInt(classAttr) : 0;
        }
        return 0;
    }

    /**
     * 使用自定义排序规则排序
     *
     * @param lsExamApplyDto
     * @param terminalType
     */
    @Override
    public void customSort(List<ExamApplyDto> lsExamApplyDto, String terminalType) {
        ConfigDto.SortSet sortSet = null;
        String sortSetConfigName = ConstantsUtil.ConfigName.CUSTOM_TABLE_ROW_SORT_SET_BY_SCHEDULE_SIGN.getKey();
        if (StringUtils.isNotBlank(terminalType) && (ConstantsUtil.TerminalType.CLINIC_IN.getType().equals(terminalType) || ConstantsUtil.TerminalType.CLINIC_OUT.getType().equals(terminalType))) {
            sortSetConfigName = ConstantsUtil.ConfigName.CUSTOM_TABLE_ROW_SORT_SET_BY_CLINICSCHE.getKey();
        }
        String sortSetStr = configServiceImpl.getConfigByName(sortSetConfigName);
        if (StringUtils.isNotBlank(sortSetStr)) {
            sortSet = JsonUtil.toBean(sortSetStr, ConfigDto.SortSet.class);
        }
        if (CollectionUtils.isNotEmpty(lsExamApplyDto) && sortSet != null) {
            // 排序字段1
            String sortField1 = sortSet.getSortField();
            // 排序方式1
            String sortOrder1 = sortSet.getSortOrder();

            String sortField2 = sortSet.getSortField2();
            String sortOrder2 = sortSet.getSortOrder2();
            lsExamApplyDto.sort((applyItem1, applyItem2) -> {
                if (Objects.isNull(applyItem1) && Objects.isNull(applyItem2)) {
                    return 0;
                } else if (Objects.isNull(applyItem1)) {
                    return -1;
                } else if (Objects.isNull(applyItem2)) {
                    return 1;
                } else {
                    // 两个对象，两个排序字段分别的值
                    String item1Field1FieldValue = "", item2Field1FieldValue = "", item1Field2FieldValue = "", item2Field2FieldValue = "";
                    try {
                        Field[] fields = applyItem1.getClass().getDeclaredFields();
                        Field[] fields_super = applyItem1.getClass().getSuperclass().getDeclaredFields();
                        Field[] fields_all = ArrayUtils.addAll(fields, fields_super);

                        List<String> fieldList;
                        // 第一个对象的字段值
                        Object item1FiledValue;
                        // 第二个对象的字段值
                        Object item2FiledVae;
                        if (StringUtils.isNotBlank(sortField1)) {
                            fieldList = CommonUtil.strToList(CommonUtil.turnFieldV2(sortField1), "，");
                            if (CollectionUtils.isNotEmpty(fieldList)) {
                                for (String filedName : fieldList) {
                                    Field currentField = Arrays.stream(fields_all).filter(x -> filedName.equals(x.getName())).findFirst().orElse(null);

                                    if (Objects.nonNull(currentField)) {
                                        currentField.setAccessible(true);
                                        item1FiledValue = currentField.get(applyItem1);
                                        if (item1FiledValue != null && StringUtils.isNotBlank(item1FiledValue.toString())) {
                                            item1Field1FieldValue += item1FiledValue + " ";
                                        }
                                        item2FiledVae = currentField.get(applyItem2);
                                        if (item2FiledVae != null && StringUtils.isNotBlank(item2FiledVae.toString())) {
                                            item2Field1FieldValue += item2FiledVae + " ";
                                        }
                                    }
                                }
                            }
                        }

                        if (StringUtils.isNotBlank(sortField2)) {
                            fieldList = CommonUtil.strToList(CommonUtil.turnFieldV2(sortField2), "，");

                            if (CollectionUtils.isNotEmpty(fieldList)) {
                                for (String filedName : fieldList) {
                                    Field currentField = Arrays.stream(fields_all).filter(x -> filedName.equals(x.getName())).findFirst().orElse(null);

                                    if (Objects.nonNull(currentField)) {
                                        currentField.setAccessible(true);
                                        item1FiledValue = currentField.get(applyItem1);
                                        if (item1FiledValue != null && StringUtils.isNotBlank(item1FiledValue.toString())) {
                                            item1Field2FieldValue += item1FiledValue + " ";
                                        }
                                        item2FiledVae = currentField.get(applyItem2);
                                        if (item2FiledVae != null && StringUtils.isNotBlank(item2FiledVae.toString())) {
                                            item2Field2FieldValue += item2FiledVae + " ";
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception var22) {
                        item1Field1FieldValue = "";
                        item2Field1FieldValue = "";
                        item1Field2FieldValue = "";
                        item2Field2FieldValue = "";
                    }
                    item1Field1FieldValue = item1Field1FieldValue.trim();
                    item2Field1FieldValue = item2Field1FieldValue.trim();
                    if (StringUtils.isBlank(sortField1)) {
                        item1Field1FieldValue = item1Field2FieldValue.trim();
                        item2Field1FieldValue = item2Field2FieldValue.trim();
                        item1Field2FieldValue = "";
                        item2Field2FieldValue = "";
                    } else {
                        item1Field2FieldValue = item1Field2FieldValue.trim();
                        item2Field2FieldValue = item2Field2FieldValue.trim();
                    }
//                    if (item1Field1FieldValue == null && item2Field1FieldValue == null) {
//                        return 0;
//                    } else if (item1Field1FieldValue == null) {
//                        return -1;
//                    } else if (item2Field1FieldValue == null) {
//                        return 1;
//                    } else {
                    // 比较两个字符串的大小进行排序
                    boolean isSortOrder1 = StringUtils.isNotBlank(sortField1) && (StringUtils.isBlank(sortOrder1) || "asc".equals(sortOrder1));
                    boolean isSortOrder2 = StringUtils.isBlank(sortField1) && StringUtils.isNotBlank(sortOrder2) && (StringUtils.isBlank(sortOrder2) || "asc".equals(sortOrder2));
                    int ascSortNo;
                    if (!isSortOrder1 && !isSortOrder2) {
                        ascSortNo = item2Field1FieldValue.compareTo(item1Field1FieldValue);
                        if (ascSortNo != 0) {
                            return ascSortNo;
                        } else if (!StringUtils.isNotBlank(item1Field2FieldValue) && !StringUtils.isNotBlank(item2Field2FieldValue)) {
                            return ascSortNo;
                        } else {
                            return !StringUtils.isBlank(sortOrder2) && !"asc".equals(sortOrder2) ? item2Field2FieldValue.compareTo(item1Field2FieldValue) : item1Field2FieldValue.compareTo(item2Field2FieldValue);
                        }
                    } else {
                        ascSortNo = item1Field1FieldValue.compareTo(item2Field1FieldValue);
                        if (ascSortNo != 0) {
                            return ascSortNo;
                        } else if (!StringUtils.isNotBlank(item1Field2FieldValue) && !StringUtils.isNotBlank(item2Field2FieldValue)) {
                            return ascSortNo;
                        } else {
                            return !StringUtils.isBlank(sortOrder2) && !"asc".equals(sortOrder2) ? item2Field2FieldValue.compareTo(item1Field2FieldValue) : item1Field2FieldValue.compareTo(item2Field2FieldValue);
                        }
                    }
//                    }
                }
            });
        }
    }

    /**
     * @param dto
     * @return
     * @description 取消预约签到
     * @author ryan.li
     * @date 2022/10/17 14:13
     */
    public JsonResult cancelSign(ExamApplyDto dto) {
        JsonResult jsonResult = new JsonResult();
        Map<String, Object> configMap = configServiceImpl.isSignScheduleByThirdWS(dto);
        boolean isSignScheduleByThirdWS = (boolean) configMap.get("isSignScheduleByThirdWS");
        String cancelUrl = String.valueOf(configMap.get("cancelUrl"));
        if (isSignScheduleByThirdWS && StringUtils.isNotBlank(cancelUrl)) {
            // 调用第三方预约报到 - 取消报到接口
            jsonResult = signScheduleByThirdWS(dto, cancelUrl, dto.getScheduledId() + "," + dto.getMergeNo(), ConstantsUtil.ActType.CANCEL_SIGN.getType());
        } else {
            Map<String, String> map = new HashMap<>();
            map.put("applyNo", dto.getScheduledId() + "," + dto.getMergeNo());
            map.put("result", "");
            map.put("desc", "");
            examApplyMapper.cancelRegister(map);
            String result = map.get("result");
            String desc = map.get("desc");
            log.info("【取消报到存储过程】result：" + result + ",desc：" + desc);
            jsonResult.setStatus(desc);
            jsonResult.setMessage(result);
        }
        return jsonResult;
    }


//    public void mobileConfigCorrelation(List<ExamApplyDto> applyDtoList, ExamApplyDto dto) {
//        DictSysparamsDto dictSysparams = new DictSysparamsDto();
//        dictSysparams.setConfigType(ConstantsUtil.ConfigType.MOBILE.getKey());
//        JsonResult result = configService.getConfigInfo(dictSysparams);
//        if (result == null || !Objects.equals(result.getStatus(), "0"))
//            return;
//        ConfigDto configDto = (ConfigDto)result.getResult();
//        Iterator<ExamApplyDto> it = applyDtoList.iterator();
//        while (it.hasNext()) {
//            ExamApplyDto ea = it.next();
//            if (configDto.getMobileScheduleExamClass() != null &&
//                    !configDto.getMobileScheduleExamClass().contains(ea.getExamClass())) {
//                if ("1".equals(configDto.getMobileNoScheduleExamClassType())) {
//                    ea.setDesc(ea.getExamClass() + configDto.getMobileNoScheduleExamClassReminder());
//                    continue;
//                }
//                if ("2".equals(configDto.getMobileNoScheduleExamClassType()))
//                    it.remove();
//                continue;
//            }
//            if (configDto.getMobileNoSchedulePatientSource() != null && configDto
//                    .getMobileNoSchedulePatientSource().contains(ea.getPatientSource())) {
//                if ("1".equals(configDto.getMobileNoSchedulePatientSourceType())) {
//                    ea.setDesc(ea.getPatientSource() + configDto.getMobileNoSchedulePatientSourceReminder());
//                    ea.setIsMerge("1");
//                    continue;
//                }
//                if ("2".equals(configDto.getMobileNoSchedulePatientSourceType()))
//                    it.remove();
//                continue;
//            }
//            if (this.configServiceImpl.isApplyDateLimit(dto.getTerminalType(), ea.getExamClass(), ea.getReqDate())) {
//                if ("1".equals(configDto.getMobileReqDateLimitType())) {
//                    ea.setDesc(configDto.getMobileReqDateLimitReminder());
//                    ea.setIsMerge("1");
//                    continue;
//                }
//                if ("2".equals(configDto.getMobileReqDateLimitType()))
//                    it.remove();
//                continue;
//            }
//            if (StringUtils.isBlank(ea.getIsMerge())) {
//                ExamApplyItemDto examApplyItemDto = new ExamApplyItemDto();
//                examApplyItemDto.setApplyNo(ea.getApplyNo());
//                List<ExamApplyItemDto> items = examApplyItemMapper.getList(examApplyItemDto);
//                for (ExamApplyItemDto item : items) {
//                    if (StringUtils.isNotBlank(item.getFlags()) && "1".equals(item.getFlags().substring(10, 11))) {
//                        if ("1".equals(configDto.getMobileNoScheduleItemType())) {
//                            ea.setDesc(configDto.getMobileNoScheduleItemReminder());
//                            ea.setIsMerge("1");
//                            continue;
//                        }
//                        if ("2".equals(configDto.getMobileNoScheduleItemType()))
//                            it.remove();
//                    }
//                }
//            }
//        }
//    }
}
